From 5e34a48442d35d63330fa4f35042b6654a63c099 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Apr 2023 16:23:19 +0200 Subject: [PATCH 001/379] Add interface for Events --- discord/interfaces/event.ts | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 discord/interfaces/event.ts diff --git a/discord/interfaces/event.ts b/discord/interfaces/event.ts new file mode 100644 index 00000000..7139a80b --- /dev/null +++ b/discord/interfaces/event.ts @@ -0,0 +1,3 @@ +export interface Event { + execute(opts: unknown): Promise; +} From 2993232838cf1b70c666ca0d604e4b254966ea75 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Apr 2023 16:54:32 +0200 Subject: [PATCH 002/379] Revert "Add interface for Events": Redundant, already specified in event-dispatcher.ts This reverts commit 5e34a48442d35d63330fa4f35042b6654a63c099. --- discord/interfaces/event.ts | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 discord/interfaces/event.ts diff --git a/discord/interfaces/event.ts b/discord/interfaces/event.ts deleted file mode 100644 index 7139a80b..00000000 --- a/discord/interfaces/event.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Event { - execute(opts: unknown): Promise; -} From 2bf8d95ac6daa5dc50d9d73e169088da37d1b6a6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Apr 2023 18:35:52 +0200 Subject: [PATCH 003/379] Update comments and make sure a class with the convention name was found --- discord/event-dispatcher.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/discord/event-dispatcher.ts b/discord/event-dispatcher.ts index e4027e52..0e87c904 100644 --- a/discord/event-dispatcher.ts +++ b/discord/event-dispatcher.ts @@ -6,7 +6,7 @@ interface EventConfig { } export interface Event { - execute(opts: any): Promise; + execute(opts: unknown): Promise; } export class EventDispatcher { @@ -18,13 +18,13 @@ export class EventDispatcher { * * @returns EventConfig[] */ - public static getEvents() { return EventDispatcher.list; } + public static getEvents(): EventConfig[] { return EventDispatcher.list; } /** * Find an Event by name * * @param name - * @returns IEvent|undefined + * @returns EvenConfig|undefined */ public static getHandler(name: string): EventConfig|undefined { return EventDispatcher.list.find((event: EventConfig) => event.name === name); @@ -32,14 +32,22 @@ export class EventDispatcher { /** * Import an event handler and add it to the list of handlers + * TODO: Make sure class implements Event * - * @param event + * @param EventConfig event * @returns Promise */ public static async add(event: EventConfig): Promise { try { - // Import the event handler - EventDispatcher.handlers[event.handler] = await import(`file://${Deno.cwd()}/src/events/${event.handler}.ts`) + // Import the source file + const handler = await import(`file://${Deno.cwd()}/src/events/${event.handler}.ts`); + + // Make sure source file has required class + if(!(`${event.name}Event` in handler)) throw Error(`No class named "${event.name}Event" could be found!`); + + + // Register handler + EventDispatcher.handlers[event.handler] = handler; } catch(e) { Logger.error(`Could not register event handler for "${event.name}": ${e.message}`, e.stack); return; @@ -51,8 +59,8 @@ export class EventDispatcher { /** * Run an instance of the Feature handler * - * @param event - * @param data + * @param string Event + * @param any data * @returns Promise */ public static async dispatch(event: string, data: any = {}): Promise { From c87a22ff7f6cb468c5a561419d56350ddb78e7d5 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Apr 2023 22:29:36 +0200 Subject: [PATCH 004/379] Add some utils. --- discord/util/find-channel-by-name.ts | 27 +++++++++++++++++++++++ discord/util/find-role-by-name.ts | 33 ++++++++++++++++++++++++++++ discord/util/mod.ts | 3 +++ discord/util/snowflake-to-date.ts | 13 +++++++++++ mod.ts | 1 + 5 files changed, 77 insertions(+) create mode 100644 discord/util/find-channel-by-name.ts create mode 100644 discord/util/find-role-by-name.ts create mode 100644 discord/util/mod.ts create mode 100644 discord/util/snowflake-to-date.ts diff --git a/discord/util/find-channel-by-name.ts b/discord/util/find-channel-by-name.ts new file mode 100644 index 00000000..c6463f8b --- /dev/null +++ b/discord/util/find-channel-by-name.ts @@ -0,0 +1,27 @@ +import { Discord } from "../discord.ts"; +import { Logger } from "../../logging/logger.ts"; + +/** + * Find a channel by its name rather than ID + * TODO: (1) Create a Map that maps channel names and snowflakes together (updates on event by gateway) + * TODO: (2) Lookup channel name in new map (acts as cache) + * TODO: (3) Obtain channel from channels list directly + * + * @param guild + * @param name + */ +export async function findChannelByName(guild: BigInt, name: string): Promise { + const channels = await Discord.getBot().helpers.getChannels(guild); + if(!channels) { + Logger.error(`Could not obtain channels for guild! (this is a bug!)`); + return null; + } + + const channel = channels.find((channel: any) => channel.name === name); + if(!channel) { + Logger.error(`No channel with name "#${name}" could be found! (did you set it up yet?)`); + return null; + } + + return channel; +} diff --git a/discord/util/find-role-by-name.ts b/discord/util/find-role-by-name.ts new file mode 100644 index 00000000..19d69390 --- /dev/null +++ b/discord/util/find-role-by-name.ts @@ -0,0 +1,33 @@ +import { Discord } from "../discord.ts"; +import { Logger } from "../../logging/logger.ts"; + +/** + * Find a role by its name rather than ID + * TODO: (1) Create a Map that maps role names and snowflakes together (updates on event by gateway) + * TODO: (2) Lookup role name in new map (acts as cache) + * TODO: (3) Obtain role from roles list directly + * TODO: Find out return type + * + * @param guild + * @param roleName + * @returns Promise + */ +export async function findRoleByName(guild: BigInt, roleName: string): Promise { + // Get a list of all roles for the guild + const roles = await Discord.getBot().helpers.getRoles(guild); + if(!roles) { + Logger.error(`Could not obtain roles for guild! (this is a bug!)`); + return null; + } + + // Find role by name + const role = roles.find((role: unknown) => role.name === roleName); + + // Check if a role was found + // Return result + if(!role) { + Logger.error(`No role with name "${roleName}" could be found! (did you set it up yet?)`); + return null; + } + return role; +} diff --git a/discord/util/mod.ts b/discord/util/mod.ts new file mode 100644 index 00000000..88fa3ce3 --- /dev/null +++ b/discord/util/mod.ts @@ -0,0 +1,3 @@ +export { findChannelByName } from "./find-channel-by-name.ts"; +export { findRoleByName } from "./find-role-by-name.ts"; +export { snowflakeToDate } from "./snowflake-to-date.ts"; diff --git a/discord/util/snowflake-to-date.ts b/discord/util/snowflake-to-date.ts new file mode 100644 index 00000000..ff144062 --- /dev/null +++ b/discord/util/snowflake-to-date.ts @@ -0,0 +1,13 @@ +export const DISCORD_EPOCH = 1420070400000; + +/** + * Turn a Discord snowflake into a date object. + * Source: https://discord.com/developers/docs/reference#snowflake-ids-in-pagination + * + * @param snowflake + * @param epoch + */ +export function snowflakeToDate(snowflake: any, epoch: number = DISCORD_EPOCH): Date { + const milliseconds = BigInt(snowflake) >> 22n; + return new Date(Number(milliseconds) + epoch); +} diff --git a/mod.ts b/mod.ts index b3fb9148..bf920ede 100644 --- a/mod.ts +++ b/mod.ts @@ -16,6 +16,7 @@ export { export type { DiscordEmbed, Intents } from "./discord/discord.ts"; export { EventDispatcher } from "./discord/event-dispatcher.ts"; export { InteractionDispatcher } from "./discord/interaction-dispatcher.ts"; +export { snowflakeToDate } from "./discord/util/snowflake-to-date.ts"; export { Logger } from "./logging/logger.ts"; export { Queue, Scheduler } from "./queue/queue.ts"; From 2d4052d651efb1a139af9a5caf10e490920b16b0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Apr 2023 22:57:19 +0200 Subject: [PATCH 005/379] Always lowercase the channel name --- discord/util/find-channel-by-name.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/util/find-channel-by-name.ts b/discord/util/find-channel-by-name.ts index c6463f8b..bc0e1889 100644 --- a/discord/util/find-channel-by-name.ts +++ b/discord/util/find-channel-by-name.ts @@ -17,7 +17,7 @@ export async function findChannelByName(guild: BigInt, name: string): Promise channel.name === name); + const channel = channels.find((channel: any) => channel.name === name.toLowerCase()); if(!channel) { Logger.error(`No channel with name "#${name}" could be found! (did you set it up yet?)`); return null; From e492ff09d9c1b5b0beb6e29f1b201dbf83daa678 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 7 May 2023 15:06:07 +0200 Subject: [PATCH 006/379] Export Event and change type to number for intents --- discord/discord.ts | 2 +- mod.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/discord/discord.ts b/discord/discord.ts index 25dc0956..61b7a16b 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -7,7 +7,7 @@ export * from "https://deno.land/x/discordeno@13.0.0/mod.ts"; export interface DiscordInitOpts { token: string; - intents: any[]; + intents: number; botId: bigint|number; withCache?: boolean; } diff --git a/mod.ts b/mod.ts index bf920ede..555f12b8 100644 --- a/mod.ts +++ b/mod.ts @@ -15,6 +15,7 @@ export { } from "./discord/discord.ts"; export type { DiscordEmbed, Intents } from "./discord/discord.ts"; export { EventDispatcher } from "./discord/event-dispatcher.ts"; +export type { Event } from "./discord/event-dispatcher.ts"; export { InteractionDispatcher } from "./discord/interaction-dispatcher.ts"; export { snowflakeToDate } from "./discord/util/snowflake-to-date.ts"; From 76ffc1fda39f24f6a6a646621aa06c1ae691312f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 4 Jun 2023 16:38:30 +0200 Subject: [PATCH 007/379] Allow disabling of cache sweepers --- discord/discord.ts | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/discord/discord.ts b/discord/discord.ts index 61b7a16b..a8ae1efc 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -10,6 +10,7 @@ export interface DiscordInitOpts { intents: number; botId: bigint|number; withCache?: boolean; + withSweeper?: boolean; } export class Discord { @@ -215,13 +216,7 @@ export class Discord { }); // Enable cache if required - if(opts.withCache === true) { - const bot = enableCachePlugin(baseBot); - enableCacheSweepers(bot); - Discord.bot = bot; - } else { - Discord.bot = baseBot; - } + Discord.bot = Discord.enableCache(baseBot, opts); } /** @@ -232,4 +227,24 @@ export class Discord { public async start(): Promise { await startBot(Discord.bot); } + + /** + * Checks whether cache needs to be enabled. + * Add both cache and sweeper if required. + * TODO: Find out type of bot + * + * @param opts + */ + private static enableCache(bot: any, opts: DiscordInitOpts): any { + // Return the bot if no cache needs to be enabled + // Otherwise enable the cache + if (!opts.withCache) return bot; + bot = enableCachePlugin(bot); + + // Return the bot if no sweeper needs to be enabled + // Otherwise enable the sweeper and return the final bot + if(!opts.withSweeper) return bot; + enableCacheSweepers(bot); + return bot; + } } From 20d50c0c058b35ea5d41aa9553c0e73d6b8439c2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 16 Jul 2023 15:15:52 +0200 Subject: [PATCH 008/379] Add class for interfacting with Loki --- communication/loki.ts | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 communication/loki.ts diff --git a/communication/loki.ts b/communication/loki.ts new file mode 100644 index 00000000..a93d6188 --- /dev/null +++ b/communication/loki.ts @@ -0,0 +1,41 @@ +import { Logger } from "../logging/logger.ts"; + +export interface LokiStream { + stream: any; + values: Array>; +} + +export default class Loki { + /** + * @param host + * @param tenant Tenant ID to use for the log item. Can be ommitted if not using multi-tenant mode. + */ + public constructor( + private readonly host: string = 'http://localhost:3100', + private readonly tenant: string = 'fake', + ) { + } + + /** + * Send a log entry to the Grafana Loki database. + * + * @param stream + */ + public async send(stream: LokiStream|LokiStream[]) { + try { + const resp = await fetch(`${this.host}/loki/api/v1/push`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Scope-OrgID': this.tenant, + }, + body: JSON.stringify({ + streams: Array.isArray(stream) ? stream : [stream], + }), + }); + if(resp.ok === false) throw Error(`Response non-OK: ${resp.statusText}`) + } catch(e) { + Logger.error(`Could not add message to Loki: ${e.message}`, e.stack); + } + } +} From cdfa4be7d877dc2520aaafe966660f4dc7dbd257 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 10:33:02 +0200 Subject: [PATCH 009/379] Move some stuff around --- discord/discord.ts | 2 +- .../event.ts} | 2 +- .../interaction.ts} | 6 ++-- discord/interaction.ts | 33 +++++++++++++++++++ mod.ts | 7 ++-- 5 files changed, 42 insertions(+), 8 deletions(-) rename discord/{event-dispatcher.ts => dispatchers/event.ts} (97%) rename discord/{interaction-dispatcher.ts => dispatchers/interaction.ts} (93%) create mode 100644 discord/interaction.ts diff --git a/discord/discord.ts b/discord/discord.ts index a8ae1efc..ef963d7d 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -1,6 +1,6 @@ import { createBot, startBot } from "https://deno.land/x/discordeno@13.0.0/mod.ts"; import { enableCachePlugin, enableCacheSweepers } from "https://deno.land/x/discordeno@13.0.0/plugins/cache/mod.ts"; -import { EventDispatcher } from "./event-dispatcher.ts"; +import { EventDispatcher } from "./dispatchers/event.ts"; import { Logger } from "../logging/logger.ts"; export * from "https://deno.land/x/discordeno@13.0.0/mod.ts"; diff --git a/discord/event-dispatcher.ts b/discord/dispatchers/event.ts similarity index 97% rename from discord/event-dispatcher.ts rename to discord/dispatchers/event.ts index 0e87c904..e5f46fe9 100644 --- a/discord/event-dispatcher.ts +++ b/discord/dispatchers/event.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../../logging/logger.ts"; interface EventConfig { name: string; diff --git a/discord/interaction-dispatcher.ts b/discord/dispatchers/interaction.ts similarity index 93% rename from discord/interaction-dispatcher.ts rename to discord/dispatchers/interaction.ts index bcd506da..20cfe025 100644 --- a/discord/interaction-dispatcher.ts +++ b/discord/dispatchers/interaction.ts @@ -1,11 +1,11 @@ -import { ApplicationCommandOption } from "https://deno.land/x/discordeno@13.0.0/mod.ts"; +import {ApplicationCommandOption, ApplicationCommandTypes} from "https://deno.land/x/discordeno@13.0.0/mod.ts"; import { Discord } from "./discord.ts"; import { Logger } from "../logging/logger.ts"; -interface InteractionConfig { +export interface InteractionConfig { name: string; description: string; - type: any; + type: ApplicationCommandTypes; options?: ApplicationCommandOption[]; handler: string; } diff --git a/discord/interaction.ts b/discord/interaction.ts new file mode 100644 index 00000000..47e2671d --- /dev/null +++ b/discord/interaction.ts @@ -0,0 +1,33 @@ +import { Discord } from "./discord.ts"; + +export default class Interaction { + protected interaction: unknown; + private _hasReplied: boolean = false; + + public constructor(opts: unknown) { + this.interaction = opts.interaction; + } + + /** + * Respond to the interaction. + * This method will automatically edit the original reply if already replied. + * + * @param data + */ + public async respond(data: unknown): Promise { + if(!this._hasReplied) { + await Discord.getBot().helpers.sendInteractionResponse( + this.interaction.id, + this.interaction.token, + data + ); + this._hasReplied = true; + return; + } + + await Discord.getBot().helpers.editInteractionResponse( + this.interaction.token, + data + ); + } +} diff --git a/mod.ts b/mod.ts index 555f12b8..11f92617 100644 --- a/mod.ts +++ b/mod.ts @@ -14,9 +14,10 @@ export { ApplicationCommandOptionTypes } from "./discord/discord.ts"; export type { DiscordEmbed, Intents } from "./discord/discord.ts"; -export { EventDispatcher } from "./discord/event-dispatcher.ts"; -export type { Event } from "./discord/event-dispatcher.ts"; -export { InteractionDispatcher } from "./discord/interaction-dispatcher.ts"; +export { EventDispatcher } from "./discord/dispatchers/event.ts"; +export type { Event } from "./discord/dispatchers/event.ts"; +export { InteractionDispatcher } from "./discord/dispatchers/interaction.ts"; +export type { InteractionConfig } from "./discord/dispatchers/interaction.ts"; export { snowflakeToDate } from "./discord/util/snowflake-to-date.ts"; export { Logger } from "./logging/logger.ts"; From 787d968cc081936d9d088de928be55651e1e0a76 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 10:54:43 +0200 Subject: [PATCH 010/379] Create a few dozen "mod.ts" files --- common/mod.ts | 4 +++ communication/mod.ts | 5 ++++ discord/dispatchers/mod.ts | 2 ++ discord/mod.ts | 11 ++++++++ logging/mod.ts | 1 + mod.ts | 50 +++++++------------------------------ queue/mod.ts | 1 + security/mod.ts | 3 +++ util/mod.ts | 5 ++++ webserver/controller/mod.ts | 1 + webserver/mod.ts | 3 +++ webserver/routing/mod.ts | 1 + websocket/mod.ts | 2 ++ 13 files changed, 48 insertions(+), 41 deletions(-) create mode 100644 common/mod.ts create mode 100644 communication/mod.ts create mode 100644 discord/dispatchers/mod.ts create mode 100644 discord/mod.ts create mode 100644 logging/mod.ts create mode 100644 queue/mod.ts create mode 100644 security/mod.ts create mode 100644 util/mod.ts create mode 100644 webserver/controller/mod.ts create mode 100644 webserver/mod.ts create mode 100644 webserver/routing/mod.ts create mode 100644 websocket/mod.ts diff --git a/common/mod.ts b/common/mod.ts new file mode 100644 index 00000000..f7bde6ec --- /dev/null +++ b/common/mod.ts @@ -0,0 +1,4 @@ +export * from "./configure.ts"; +export * from "./cron.ts"; +export * from "./env.ts"; +export * from "./time.ts"; diff --git a/communication/mod.ts b/communication/mod.ts new file mode 100644 index 00000000..aa54c8b7 --- /dev/null +++ b/communication/mod.ts @@ -0,0 +1,5 @@ +export * from "./druid.ts"; +export * from "./loki.ts"; +export * from "./ntfy.ts"; +export * from "./rcon.ts"; +export * from "./redis.ts"; diff --git a/discord/dispatchers/mod.ts b/discord/dispatchers/mod.ts new file mode 100644 index 00000000..160d1e25 --- /dev/null +++ b/discord/dispatchers/mod.ts @@ -0,0 +1,2 @@ +export * from "./event.ts"; +export * from "./interaction.ts"; diff --git a/discord/mod.ts b/discord/mod.ts new file mode 100644 index 00000000..f9c336ac --- /dev/null +++ b/discord/mod.ts @@ -0,0 +1,11 @@ +export * from "./dispatchers/mod.ts"; +export * from "./util/mod.ts"; + +export { + Discord, + InteractionResponseTypes, + ApplicationCommandTypes, + ApplicationCommandOptionTypes +} from "./discord.ts"; + +export type { DiscordEmbed, Intents } from "./discord.ts"; diff --git a/logging/mod.ts b/logging/mod.ts new file mode 100644 index 00000000..8824d1b2 --- /dev/null +++ b/logging/mod.ts @@ -0,0 +1 @@ +export * from "./logger.ts"; diff --git a/mod.ts b/mod.ts index 11f92617..288a77fd 100644 --- a/mod.ts +++ b/mod.ts @@ -1,41 +1,9 @@ -export { Configure } from "./common/configure.ts"; -export { cron } from "./common/cron.ts"; -export { env } from "./common/env.ts"; -export { Time } from "./common/time.ts"; - -export { Ntfy } from "./communication/ntfy.ts"; -export { RCON } from "./communication/rcon.ts"; -export { Redis } from "./communication/redis.ts"; - -export { - Discord, - InteractionResponseTypes, - ApplicationCommandTypes, - ApplicationCommandOptionTypes -} from "./discord/discord.ts"; -export type { DiscordEmbed, Intents } from "./discord/discord.ts"; -export { EventDispatcher } from "./discord/dispatchers/event.ts"; -export type { Event } from "./discord/dispatchers/event.ts"; -export { InteractionDispatcher } from "./discord/dispatchers/interaction.ts"; -export type { InteractionConfig } from "./discord/dispatchers/interaction.ts"; -export { snowflakeToDate } from "./discord/util/snowflake-to-date.ts"; - -export { Logger } from "./logging/logger.ts"; -export { Queue, Scheduler } from "./queue/queue.ts"; - -export { Hash, Algorithms } from "./security/hash.ts"; -export { Password } from "./security/password.ts"; -export { Random } from "./security/random.ts"; - -export { CheckSource } from "./util/check-source.ts"; -export { tokenizer } from "./util/tokenizer.ts"; -export { lcfirst } from "./util/lcfirst.ts"; -export { ucfirst } from "./util/ucfirst.ts"; - -export { Controller } from "./webserver/controller/controller.ts"; -export { Router } from "./webserver/routing/router.ts"; -export { Webserver } from "./webserver/webserver.ts"; -export type { RouteArgs } from "./webserver/routing/router.ts"; - -export { Websocket } from "./websocket/websocket.ts"; -export { Events } from "./websocket/events.ts"; +export * from "./common/mod.ts"; +export * from "./communication/mod.ts"; +export * from "./discord/mod.ts"; +export * from "./logging/mod.ts"; +export * from "./queue/mod.ts"; +export * from "./security/mod.ts"; +export * from "./util/mod.ts"; +export * from "./webserver/mod.ts"; +export * from "./websocket/mod.ts"; diff --git a/queue/mod.ts b/queue/mod.ts new file mode 100644 index 00000000..dfe032f0 --- /dev/null +++ b/queue/mod.ts @@ -0,0 +1 @@ +export * from "./queue.ts"; diff --git a/security/mod.ts b/security/mod.ts new file mode 100644 index 00000000..6dbf928e --- /dev/null +++ b/security/mod.ts @@ -0,0 +1,3 @@ +export * from "./hash.ts"; +export * from "./password.ts"; +export * from "./random.ts"; diff --git a/util/mod.ts b/util/mod.ts new file mode 100644 index 00000000..bcd0ddb5 --- /dev/null +++ b/util/mod.ts @@ -0,0 +1,5 @@ +export * from "./check-source.ts"; +export * from "./lcfirst.ts"; +export * from "./time-string.ts"; +export * from "./tokenizer.ts"; +export * from "./ucfirst.ts"; diff --git a/webserver/controller/mod.ts b/webserver/controller/mod.ts new file mode 100644 index 00000000..0632fe9d --- /dev/null +++ b/webserver/controller/mod.ts @@ -0,0 +1 @@ +export * from "./controller.ts"; diff --git a/webserver/mod.ts b/webserver/mod.ts new file mode 100644 index 00000000..43981f43 --- /dev/null +++ b/webserver/mod.ts @@ -0,0 +1,3 @@ +export * from "./controller/mod.ts"; +export * from "./routing/mod.ts"; +export * from "./webserver.ts"; diff --git a/webserver/routing/mod.ts b/webserver/routing/mod.ts new file mode 100644 index 00000000..d18015da --- /dev/null +++ b/webserver/routing/mod.ts @@ -0,0 +1 @@ +export * from "./router.ts"; diff --git a/websocket/mod.ts b/websocket/mod.ts new file mode 100644 index 00000000..c162a2da --- /dev/null +++ b/websocket/mod.ts @@ -0,0 +1,2 @@ +export * from "./authenticator.ts"; +export * from "./events.ts"; From 86950dfaade1910901b9d95a772f0e722fc6bc2c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 12:12:01 +0200 Subject: [PATCH 011/379] Add CouchDB communication class --- communication/couchdb.ts | 169 +++++++++++++++++++++++++++++++++++++++ communication/mod.ts | 1 + 2 files changed, 170 insertions(+) create mode 100644 communication/couchdb.ts diff --git a/communication/couchdb.ts b/communication/couchdb.ts new file mode 100644 index 00000000..98b48a33 --- /dev/null +++ b/communication/couchdb.ts @@ -0,0 +1,169 @@ +interface Auth { + username: string; + password: string; +} + +export interface CouchResponse { + status: number; + statusText: string; + data?: any; + error?: { + error: string; + reason: string; + }; +} + +interface CouchOverrides { + method?: string; +} + +export default class CouchDB { + private auth = ''; + + public constructor( + private readonly host: string = 'http://localhost:5984', + private readonly database: string, + auth: Auth = {username: '', password: ''}, + ) { + this.auth = btoa(`${auth.username}:${auth.password}`); + } + + /** + * Update the username for this instance. + * This does *not* update the username on the server. + * + * @param username + */ + public set username(username: string): void { + // Get the password from the data + const password = atob(this.auth).split(':')[1]; + + // Update auth string + this.auth = btoa(`${username}:${password}`); + } + + /** + * Update the password for this instance. + * This does *not* update the password on the server. + * + * @param password + */ + public set password(password: string): void { + // Get the password from the data + const username = atob(this.auth).split(':')[0]; + + // Update auth string + this.auth = btoa(`${username}:${password}`); + } + + /** + * Get a document from the database. + * + * @param id + */ + public async get(id: string): Promise { + return await this.raw(id); + } + + /** + * Insert a document into the database. + * + * @param data + */ + public async insert(data: any): Promise { + return await this.raw('', data); + } + + /** + * Update a document in the database. + * This is only useful if you know the latest revision, otherwise see the "upsert" method instead. + * + * @param id + * @param revision + * @param data + */ + public async update(id: string, revision: string, data: any): Promise { + // Make sure the id and revision are set in the data + if(!data['_id'] || data['_id'] !== id) data['_id'] = id; + if(!data['_rev'] || data['_rev'] !== revision) data['_rev'] = revision; + + return await this.raw(id, data, { method: 'PUT' }); + } + + /** + * Update or insert a document into the database. + * This method will automatically check if an existing document exists and try to update it. + * If no document exists, it will be created instead. + * + * @param id + * @param data + */ + public async upsert(id: string, data: any): Promise { + // Check if a document already exists + // Insert a new document if not + const exists = await this.raw(id, null, { method: 'HEAD' }); + if(exists.status === 404) { + data['_id'] = id; + return await this.insert(data); + } + + // Update the document + return await this.update(id, exists.data['_rev'], data); + } + + /** + * Delete a document from the database. + * + * @param id + */ + public async delete(id: string, revision: string): Promise { + return await this.raw(`${id}?rev=${revision}`, null, { method: 'DELETE' }); + } + + /** + * Main request handler. + * This method is used for most of our other methods as well. + * + * @param endpoint + * @param body + * @param overrides + */ + public async raw(endpoint: string, body: any = null, overrides: CouchOverrides = {}): Promise { + // Start building opts + const opts: any = { + method: overrides['method'] ? overrides['method'] : 'GET', + headers: { + Authorization: `Basic ${this.auth}`, + } + }; + + // Add body if specified + if(body !== null) { + opts['method'] = opts.method !== 'GET' ? opts.method : 'POST'; + opts['body'] = JSON.stringify(body); + opts.headers['Content-Type'] = 'application/json'; + } + + // Make sure the endpoint starts with a leading slash + if(endpoint.charAt(0) !== '/' && endpoint !== '') endpoint = `/${endpoint}`; + + // Send our request and get the response + const resp = await fetch(`${this.host}/${this.database}${endpoint}`, opts); + const data = await resp.json(); + + // Prepare our CouchResponse + const couchResponse = { + status: resp.status, + statusText: resp.statusText, + }; + + // Check whether we have an error + if(resp.ok) { + couchResponse['data'] = data; + } else { + couchResponse['error'] = data; + } + + return couchResponse; + } +} diff --git a/communication/mod.ts b/communication/mod.ts index aa54c8b7..2a2d8e82 100644 --- a/communication/mod.ts +++ b/communication/mod.ts @@ -1,3 +1,4 @@ +export * from "./couchdb.ts"; export * from "./druid.ts"; export * from "./loki.ts"; export * from "./ntfy.ts"; From 8fec4eb8587673ad9171fe0c17825e3f80bce16a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 12:12:13 +0200 Subject: [PATCH 012/379] Fix some minor errors --- discord/dispatchers/interaction.ts | 8 ++------ discord/interaction.ts | 2 +- discord/mod.ts | 2 ++ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/discord/dispatchers/interaction.ts b/discord/dispatchers/interaction.ts index 20cfe025..d98fc840 100644 --- a/discord/dispatchers/interaction.ts +++ b/discord/dispatchers/interaction.ts @@ -1,6 +1,6 @@ import {ApplicationCommandOption, ApplicationCommandTypes} from "https://deno.land/x/discordeno@13.0.0/mod.ts"; -import { Discord } from "./discord.ts"; -import { Logger } from "../logging/logger.ts"; +import { Discord } from "../discord.ts"; +import { Logger } from "../../logging/logger.ts"; export interface InteractionConfig { name: string; @@ -10,10 +10,6 @@ export interface InteractionConfig { handler: string; } -export interface Interaction { - execute(): Promise; -} - export class InteractionDispatcher { private static list: InteractionConfig[] = []; private static handlers: any = {}; diff --git a/discord/interaction.ts b/discord/interaction.ts index 47e2671d..5ed60eb7 100644 --- a/discord/interaction.ts +++ b/discord/interaction.ts @@ -1,6 +1,6 @@ import { Discord } from "./discord.ts"; -export default class Interaction { +export class Interaction { protected interaction: unknown; private _hasReplied: boolean = false; diff --git a/discord/mod.ts b/discord/mod.ts index f9c336ac..c61b5d06 100644 --- a/discord/mod.ts +++ b/discord/mod.ts @@ -1,6 +1,8 @@ export * from "./dispatchers/mod.ts"; export * from "./util/mod.ts"; +export { Interaction } from "./interaction.ts"; + export { Discord, InteractionResponseTypes, From fa9d5c3e3dce83253608bfc5081e18cdd9200534 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 12:21:14 +0200 Subject: [PATCH 013/379] Fix more errors --- communication/couchdb.ts | 2 +- discord/mod.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 98b48a33..0ad027c4 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -17,7 +17,7 @@ interface CouchOverrides { method?: string; } -export default class CouchDB { +export class CouchDB { private auth = ''; public constructor( diff --git a/discord/mod.ts b/discord/mod.ts index c61b5d06..b2008976 100644 --- a/discord/mod.ts +++ b/discord/mod.ts @@ -1,7 +1,7 @@ export * from "./dispatchers/mod.ts"; export * from "./util/mod.ts"; -export { Interaction } from "./interaction.ts"; +export * from "./interaction.ts"; export { Discord, From 062128f24dbda58a70cf9cc398db005dd26c08c1 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 12:35:57 +0200 Subject: [PATCH 014/379] Replace Cron with Croner --- common/cron.ts | 141 +------------------------------------------------ 1 file changed, 1 insertion(+), 140 deletions(-) diff --git a/common/cron.ts b/common/cron.ts index 2753eaa4..ea5e3560 100644 --- a/common/cron.ts +++ b/common/cron.ts @@ -1,140 +1 @@ -import { Time } from './time.ts'; - -type JobType = () => void; - -enum TIME_PART { - SECOND = 'SECOND', - MINUTE = 'MINUTE', - HOUR = 'HOUR', - DAY_OF_WEEK = 'DAY_OF_WEEK', - DAY_OF_MONTH = 'DAY_OF_MONTH', - MONTH = 'MONTH', -} - -const schedules = new Map>(); - -let schedulerTimeIntervalID: ReturnType = 0; -let shouldStopRunningScheduler = false; - -export const cron = (schedule: string = '', job: JobType) => { - let jobs = schedules.has(schedule) - ? [...(schedules.get(schedule) || []), job] - : [job]; - schedules.set(schedule, jobs); -}; - -const isRange = (text: string) => /^\d\d?\-\d\d?$/.test(text); - -const getRange = (min: number, max: number) => { - const numRange = []; - let lowerBound = min; - while (lowerBound <= max) { - numRange.push(lowerBound); - lowerBound += 1; - } - return numRange; -}; - -const { DAY_OF_MONTH, DAY_OF_WEEK, HOUR, MINUTE, MONTH, SECOND } = TIME_PART; - -const getTimePart = (date: Date, type: TIME_PART): number => - ({ - [SECOND]: date.getSeconds(), - [MINUTE]: date.getMinutes(), - [HOUR]: date.getHours(), - [MONTH]: date.getMonth() + 1, - [DAY_OF_WEEK]: date.getDay(), - [DAY_OF_MONTH]: date.getDate(), - }[type]); - -const isMatched = (date: Date, timeFlag: string, type: TIME_PART): boolean => { - const timePart = getTimePart(date, type); - - if (timeFlag === '*') { - return true; - } else if (Number(timeFlag) === timePart) { - return true; - } else if (timeFlag.includes('/')) { - const [_, executeAt = '1'] = timeFlag.split('/'); - return timePart % Number(executeAt) === 0; - } else if (timeFlag.includes(',')) { - const list = timeFlag.split(',').map((num: string) => parseInt(num)); - return list.includes(timePart); - } else if (isRange(timeFlag)) { - const [start, end] = timeFlag.split('-'); - const list = getRange(parseInt(start), parseInt(end)); - return list.includes(timePart); - } - return false; -}; - -export const validate = (schedule: string, date: Date = new Time().getTime) => { - // @ts-ignore - const timeObj: Record = {}; - - const [ - dayOfWeek, - month, - dayOfMonth, - hour, - minute, - second = '01', - ] = schedule.split(' ').reverse(); - - const cronValues = { - [SECOND]: second, - [MINUTE]: minute, - [HOUR]: hour, - [MONTH]: month, - [DAY_OF_WEEK]: dayOfWeek, - [DAY_OF_MONTH]: dayOfMonth, - }; - - for (const key in cronValues) { - timeObj[key as TIME_PART] = isMatched( - date, - cronValues[key as TIME_PART], - key as TIME_PART, - ); - } - - const didMatch = Object.values(timeObj).every(Boolean); - return { - didMatch, - entries: timeObj, - }; -}; - -const executeJobs = () => { - const date = new Time().getTime; - schedules.forEach((jobs, schedule) => { - if (validate(schedule, date).didMatch) { - jobs.forEach((job) => { - job() - }); - } - }); -}; - -const runScheduler = () => { - schedulerTimeIntervalID = setInterval(() => { - if (shouldStopRunningScheduler) { - clearInterval(schedulerTimeIntervalID); - return; - } - executeJobs(); - }, 1000); -}; - -export const start = () => { - if (shouldStopRunningScheduler) { - shouldStopRunningScheduler = false; - runScheduler(); - } -}; - -export const stop = () => { - shouldStopRunningScheduler = true; -}; - -runScheduler(); +export { Cron } from "https://deno.land/x/croner@5.3.4/src/croner.js"; From e0d280eac7538e0cb4c057bb4a4f10a06e9acbf4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 12:36:10 +0200 Subject: [PATCH 015/379] Remove env from "mod.ts" --- common/mod.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/common/mod.ts b/common/mod.ts index f7bde6ec..a41e1d0c 100644 --- a/common/mod.ts +++ b/common/mod.ts @@ -1,4 +1,3 @@ export * from "./configure.ts"; export * from "./cron.ts"; -export * from "./env.ts"; export * from "./time.ts"; From b349bd947ccc6f4ca1df74839a0dc7191a992df8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 12:40:35 +0200 Subject: [PATCH 016/379] Magic with exports --- discord/mod.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/discord/mod.ts b/discord/mod.ts index b2008976..50e3c2bf 100644 --- a/discord/mod.ts +++ b/discord/mod.ts @@ -10,4 +10,12 @@ export { ApplicationCommandOptionTypes } from "./discord.ts"; -export type { DiscordEmbed, Intents } from "./discord.ts"; +export { + Intents, + AuditLogEvents, + ApplicationCommandFlags +} from "https://deno.land/x/discordeno@13.0.0/mod.ts"; + +export type { + DiscordEmbed +} from "https://deno.land/x/discordeno@13.0.0/mod.ts"; From c28fbd17daa752d72e2b5ffedc5cc278dc617e20 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 12:46:09 +0200 Subject: [PATCH 017/379] Fix some todos --- discord/discord.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/discord/discord.ts b/discord/discord.ts index ef963d7d..9f9536bf 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -1,5 +1,9 @@ -import { createBot, startBot } from "https://deno.land/x/discordeno@13.0.0/mod.ts"; -import { enableCachePlugin, enableCacheSweepers } from "https://deno.land/x/discordeno@13.0.0/plugins/cache/mod.ts"; +import { createBot, startBot, Bot } from "https://deno.land/x/discordeno@13.0.0/mod.ts"; +import { + BotWithCache, + enableCachePlugin, + enableCacheSweepers +} from "https://deno.land/x/discordeno@13.0.0/plugins/cache/mod.ts"; import { EventDispatcher } from "./dispatchers/event.ts"; import { Logger } from "../logging/logger.ts"; @@ -14,18 +18,15 @@ export interface DiscordInitOpts { } export class Discord { - protected static bot: any; + protected static bot: Bot|undefined; protected token = ''; protected intents: any; protected botId = BigInt(0); /** * Return the instance of the Discord bot connection - * TODO: Find out type of Discord.bot - * - * @returns any */ - public static getBot(): any { return Discord.bot; } + public static getBot(): Bot|undefined { return Discord.bot; } public constructor(opts: DiscordInitOpts) { // Make sure required parameters are present @@ -225,17 +226,18 @@ export class Discord { * @returns Promise */ public async start(): Promise { + if(!Discord.bot) throw Error('Bot is not configured!'); await startBot(Discord.bot); } /** * Checks whether cache needs to be enabled. * Add both cache and sweeper if required. - * TODO: Find out type of bot - * + * + * @param bot * @param opts */ - private static enableCache(bot: any, opts: DiscordInitOpts): any { + private static enableCache(bot: Bot, opts: DiscordInitOpts): Bot|BotWithCache { // Return the bot if no cache needs to be enabled // Otherwise enable the cache if (!opts.withCache) return bot; @@ -244,7 +246,7 @@ export class Discord { // Return the bot if no sweeper needs to be enabled // Otherwise enable the sweeper and return the final bot if(!opts.withSweeper) return bot; - enableCacheSweepers(bot); + enableCacheSweepers(bot as BotWithCache); return bot; } } From 7c757153920cb80381a7a75c1e6bee9ffe8a49f5 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 16:46:35 +0200 Subject: [PATCH 018/379] Load interactions by convention --- discord/discord.ts | 2 ++ discord/dispatchers/interaction.ts | 46 ++++++++++++++++++++++++++++++ util/folder-exists.ts | 9 ++++++ util/is-ts.ts | 5 ++++ util/mod.ts | 2 ++ 5 files changed, 64 insertions(+) create mode 100644 util/folder-exists.ts create mode 100644 util/is-ts.ts diff --git a/discord/discord.ts b/discord/discord.ts index 9f9536bf..987467a2 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -6,6 +6,7 @@ import { } from "https://deno.land/x/discordeno@13.0.0/plugins/cache/mod.ts"; import { EventDispatcher } from "./dispatchers/event.ts"; import { Logger } from "../logging/logger.ts"; +import { InteractionDispatcher } from "./dispatchers/interaction.ts"; export * from "https://deno.land/x/discordeno@13.0.0/mod.ts"; @@ -227,6 +228,7 @@ export class Discord { */ public async start(): Promise { if(!Discord.bot) throw Error('Bot is not configured!'); + await InteractionDispatcher.load(); await startBot(Discord.bot); } diff --git a/discord/dispatchers/interaction.ts b/discord/dispatchers/interaction.ts index d98fc840..f806a906 100644 --- a/discord/dispatchers/interaction.ts +++ b/discord/dispatchers/interaction.ts @@ -1,6 +1,8 @@ import {ApplicationCommandOption, ApplicationCommandTypes} from "https://deno.land/x/discordeno@13.0.0/mod.ts"; import { Discord } from "../discord.ts"; import { Logger } from "../../logging/logger.ts"; +import { isTs } from "../../util/is-ts.ts"; +import { folderExists } from "../../util/folder-exists.ts"; export interface InteractionConfig { name: string; @@ -88,4 +90,48 @@ export class InteractionDispatcher { Logger.error(`Could not dispatch interaction "${interaction}": "${e.message}"`, e.stack); } } + + /** + * Load all interactions from the required directory. + * By convention, this will be "src/interactions". + */ + public static async load(): Promise { + // Create our directory string + const dir = `${Deno.cwd()}/src/interactions`; + Logger.debug(`Loading interactions from "${dir}"...`); + + // Make sure the interactions directory exists + if(!folderExists(dir)) { + Logger.warning(`"${dir}" does not exist, no interactions to load`); + return; + } + + // Get a list of all files + const files = await Deno.readDir(dir); + + // Load all interactions + const promiseQueue: Promise[] = []; + for await(const file of files) { + if(!isTs(file.name)) { + Logger.debug(`File "${file.name}" is not a TS file, skipping...`); + continue; + } + + // Import each file as a module + const module = await import(`file:///${dir}/${file.name}`); + + // Make sure module has a "config" exposed + if(!('config' in module)) { + Logger.warning(`Could not find config in "${interaction.name}", skipping...`); + continue; + } + + // Register in the dispatcher + module.config['handler'] = module.config.name; + promiseQueue.push(InteractionDispatcher.add(module.config)); + } + + // Wait until the promise queue has cleared + await Promise.all(promiseQueue); + } } diff --git a/util/folder-exists.ts b/util/folder-exists.ts new file mode 100644 index 00000000..bc069df4 --- /dev/null +++ b/util/folder-exists.ts @@ -0,0 +1,9 @@ +export async function folderExists(path: string): boolean { + try { + const target = await Deno.stat(path); + return target.isDirectory; + } catch(e) { + if(e instanceof Deno.errors.NotFound) return false; + throw e; + } +} diff --git a/util/is-ts.ts b/util/is-ts.ts new file mode 100644 index 00000000..eade59b9 --- /dev/null +++ b/util/is-ts.ts @@ -0,0 +1,5 @@ +export function isTs(name: string): boolean { + const pos = name.lastIndexOf("."); + if(pos < 1) return false; + return name.slice(pos + 1) === 'ts'; +} diff --git a/util/mod.ts b/util/mod.ts index bcd0ddb5..c8511685 100644 --- a/util/mod.ts +++ b/util/mod.ts @@ -1,4 +1,6 @@ export * from "./check-source.ts"; +export * from "./folder-exists.ts"; +export * from "./is-ts.ts"; export * from "./lcfirst.ts"; export * from "./time-string.ts"; export * from "./tokenizer.ts"; From f6a9108491864511b7522275ac087ad8eede6aa5 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 16:51:37 +0200 Subject: [PATCH 019/379] Change log from warning to debug --- discord/dispatchers/interaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/dispatchers/interaction.ts b/discord/dispatchers/interaction.ts index f806a906..08124ade 100644 --- a/discord/dispatchers/interaction.ts +++ b/discord/dispatchers/interaction.ts @@ -76,7 +76,7 @@ export class InteractionDispatcher { // Get the handler const handler = InteractionDispatcher.getHandler(interaction); if(!handler) { - Logger.warning(`Interaction "${interaction}" does not exist! (did you register it?)`); + Logger.debug(`Interaction "${interaction}" does not exist! (did you register it?)`); return; } From 9255bf725b7133492c30f1b721c0588ea4de7496 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 16:55:28 +0200 Subject: [PATCH 020/379] Add debug statement --- discord/dispatchers/interaction.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/discord/dispatchers/interaction.ts b/discord/dispatchers/interaction.ts index 08124ade..a9508e30 100644 --- a/discord/dispatchers/interaction.ts +++ b/discord/dispatchers/interaction.ts @@ -118,6 +118,7 @@ export class InteractionDispatcher { } // Import each file as a module + Logger.debug(`Loading "${file.name}"...`); const module = await import(`file:///${dir}/${file.name}`); // Make sure module has a "config" exposed From 4dda83b45597672995c3ee611f6ffeee371e66b4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 17:50:35 +0200 Subject: [PATCH 021/379] Automatically load events from directory --- discord/discord.ts | 1 + discord/dispatchers/event.ts | 56 +++++++++++++++++++++++++++++++++++- util/inflector.ts | 45 +++++++++++++++++++++++++++++ util/mod.ts | 1 + 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 util/inflector.ts diff --git a/discord/discord.ts b/discord/discord.ts index 987467a2..71936b8b 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -228,6 +228,7 @@ export class Discord { */ public async start(): Promise { if(!Discord.bot) throw Error('Bot is not configured!'); + await EventDispatcher.load(); await InteractionDispatcher.load(); await startBot(Discord.bot); } diff --git a/discord/dispatchers/event.ts b/discord/dispatchers/event.ts index e5f46fe9..4fd19ae3 100644 --- a/discord/dispatchers/event.ts +++ b/discord/dispatchers/event.ts @@ -1,4 +1,7 @@ import { Logger } from "../../logging/logger.ts"; +import { folderExists } from "../../util/folder-exists.ts"; +import { isTs } from "../../util/is-ts.ts"; +import { Inflector } from "../../util/inflector.ts"; interface EventConfig { name: string; @@ -45,7 +48,6 @@ export class EventDispatcher { // Make sure source file has required class if(!(`${event.name}Event` in handler)) throw Error(`No class named "${event.name}Event" could be found!`); - // Register handler EventDispatcher.handlers[event.handler] = handler; } catch(e) { @@ -78,4 +80,56 @@ export class EventDispatcher { Logger.error(`Could not dispatch event "${event}": "${e.message}"`, e.stack); } } + + /** + * Load all events from the required directory. + * By convention, this will be "src/events". + */ + public static async load(): Promise { + // Create our directory string + const dir = `${Deno.cwd()}/src/events`; + Logger.debug(`Loading events from "${dir}"...`); + + // Make sure the interactions directory exists + if(!folderExists(dir)) { + Logger.warning(`"${dir}" does not exist, no events to load.`); + return; + } + + // Get a list of all files + const files = await Deno.readDir(dir); + + // Load all interactions + const promiseQueue: Promise[] = []; + for await(const file of files) { + if(!isTs(file.name)) { + Logger.debug(`File "${file.name}" is not a TS file, skipping...`); + continue; + } + + // Import the file as a module + Logger.debug(`Loading "${file.name}"...`); + const module = await import(`file:///${dir}/${file.name}`); + + // Make sure the file contains a valid handler + const name = file.name.replace('.ts', ''); + const eventName = Inflector.pascalize(name, '-'); + const className = `${eventName}Event`; + if(!(className in module)) { + Logger.warning(`Could not find ${className} in "${file.name}", skipping...`); + continue; + } + + // Register in the dispatcher + promiseQueue.push( + EventDispatcher.add({ + name: eventName, + handler: name, + }) + ); + } + + // Wait until the promise queue has cleared + await Promise.all(promiseQueue); + } } diff --git a/util/inflector.ts b/util/inflector.ts new file mode 100644 index 00000000..62e18681 --- /dev/null +++ b/util/inflector.ts @@ -0,0 +1,45 @@ +/** + * Idea and code primarily based on CakePHP's code. + */ +export class Inflector { + + public static ucfirst(input: string): string { + return input.charAt(0).toUpperCase() + input.slice(1); + } + + public static lcfirst(input: string): string { + return input.charAt(0).toLowerCase() + input.slice(1); + } + + /** + * Turn a string into PascalCase. + * + * @param input + */ + public static pascalize(input: string, delimiter: string = '_'): string { + return Inflector + .humanize(input, delimiter) + .replaceAll(' ', ''); + } + + /** + * Return the input lower_case_delimited_string as "A Human Readable String". + * (Underscores are replaced by spaces and capitalized following words.) + * + * @param input + * @param delimiter + */ + public static humanize(input: string, delimiter: string = '_'): string { + // Split our string into tokens + const tokens: string[] = input + .split(delimiter); + + // Uppercase each of the tokens + for(let i = 0; i < tokens.length; i++) { + tokens[i] = Inflector.ucfirst(tokens[i]); + } + + // Join tokens into a string and return + return tokens.join(' '); + } +} diff --git a/util/mod.ts b/util/mod.ts index c8511685..2972944d 100644 --- a/util/mod.ts +++ b/util/mod.ts @@ -1,5 +1,6 @@ export * from "./check-source.ts"; export * from "./folder-exists.ts"; +export * from "./inflector.ts"; export * from "./is-ts.ts"; export * from "./lcfirst.ts"; export * from "./time-string.ts"; From 91ca284921844f8c5438d11be902c96b912a9292 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 17:50:51 +0200 Subject: [PATCH 022/379] Deprecate ucfirst and lcfirst in favour of the Inflector class --- util/lcfirst.ts | 3 +++ util/ucfirst.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/util/lcfirst.ts b/util/lcfirst.ts index 4fd59743..3cba0958 100644 --- a/util/lcfirst.ts +++ b/util/lcfirst.ts @@ -1,3 +1,6 @@ +import { Logger } from "../logging/logger.ts"; + export function lcfirst(input: string): string { + Logger.debug('Usage of "util/lcfirst" is deprecated, please use "util/inflector#lcfirst" instead.'); return input.charAt(0).toLowerCase() + input.slice(1); } diff --git a/util/ucfirst.ts b/util/ucfirst.ts index 421ce516..4dcd50ca 100644 --- a/util/ucfirst.ts +++ b/util/ucfirst.ts @@ -1,3 +1,6 @@ +import { Logger } from "../logging/logger.ts"; + export function ucfirst(input: string): string { + Logger.debug('Usage of "util/ucfirst" is deprecated, please use "util/inflector#ucfirst" instead.'); return input.charAt(0).toUpperCase() + input.slice(1); } From 74baec39b0e5a567b0f8625818a715f5f8306263 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 19:13:41 +0200 Subject: [PATCH 023/379] use the inflector for the InteractionDispatcher --- discord/dispatchers/interaction.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/discord/dispatchers/interaction.ts b/discord/dispatchers/interaction.ts index a9508e30..75e8abcc 100644 --- a/discord/dispatchers/interaction.ts +++ b/discord/dispatchers/interaction.ts @@ -3,6 +3,7 @@ import { Discord } from "../discord.ts"; import { Logger } from "../../logging/logger.ts"; import { isTs } from "../../util/is-ts.ts"; import { folderExists } from "../../util/folder-exists.ts"; +import { Inflector } from "../../util/inflector.ts"; export interface InteractionConfig { name: string; @@ -81,7 +82,7 @@ export class InteractionDispatcher { } // Create an instance of the handler - const controller = new InteractionDispatcher.handlers[handler.handler][`${interaction[0].toUpperCase() + interaction.slice(1)}Interaction`](data); + const controller = new InteractionDispatcher.handlers[handler.handler][`${Inflector.pascalize(interaction)}Interaction`](data); // Execute the handler's execute method try { From 7aa1b19d1cbce509568e8de62b5e47e15b103cfe Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 19:31:30 +0200 Subject: [PATCH 024/379] Add some comments --- util/inflector.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/util/inflector.ts b/util/inflector.ts index 62e18681..7419db06 100644 --- a/util/inflector.ts +++ b/util/inflector.ts @@ -2,11 +2,21 @@ * Idea and code primarily based on CakePHP's code. */ export class Inflector { - + + /** + * Return input string with first character uppercased. + * + * @param input + */ public static ucfirst(input: string): string { return input.charAt(0).toUpperCase() + input.slice(1); } - + + /** + * Return input string with first character lowercased. + * + * @param input + */ public static lcfirst(input: string): string { return input.charAt(0).toLowerCase() + input.slice(1); } From b003a65ae1594202c7bcb29923b914d1308a192e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 19:31:38 +0200 Subject: [PATCH 025/379] Remove assignment --- discord/dispatchers/event.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/discord/dispatchers/event.ts b/discord/dispatchers/event.ts index 4fd19ae3..551a1ac0 100644 --- a/discord/dispatchers/event.ts +++ b/discord/dispatchers/event.ts @@ -112,8 +112,7 @@ export class EventDispatcher { const module = await import(`file:///${dir}/${file.name}`); // Make sure the file contains a valid handler - const name = file.name.replace('.ts', ''); - const eventName = Inflector.pascalize(name, '-'); + const eventName = Inflector.pascalize(file.name.replace('.ts', ''), '-'); const className = `${eventName}Event`; if(!(className in module)) { Logger.warning(`Could not find ${className} in "${file.name}", skipping...`); From 9439ca944763cfa177314582af16c0b9e87fb4e8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 20:00:17 +0200 Subject: [PATCH 026/379] Rename tests --- tests/common/{configure.ts => configure.test.ts} | 0 tests/queue/{queue.ts => queue.test.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/common/{configure.ts => configure.test.ts} (100%) rename tests/queue/{queue.ts => queue.test.ts} (100%) diff --git a/tests/common/configure.ts b/tests/common/configure.test.ts similarity index 100% rename from tests/common/configure.ts rename to tests/common/configure.test.ts diff --git a/tests/queue/queue.ts b/tests/queue/queue.test.ts similarity index 100% rename from tests/queue/queue.ts rename to tests/queue/queue.test.ts From e2540272f32f1edf2a25e55ee52d92e0d27b8174 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 20:00:27 +0200 Subject: [PATCH 027/379] Write test for the inflector --- tests/util/inflector.test.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/util/inflector.test.ts diff --git a/tests/util/inflector.test.ts b/tests/util/inflector.test.ts new file mode 100644 index 00000000..d018b459 --- /dev/null +++ b/tests/util/inflector.test.ts @@ -0,0 +1,28 @@ +import { Inflector } from "../../util/inflector.ts"; +import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; + +Deno.test("Inflector Test", async (t) => { + await t.step("ucfirst", () => { + assertEquals(Inflector.ucfirst('hello world'), 'Hello world'); + assertEquals(Inflector.ucfirst('hello World'), 'Hello World'); + }); + + await t.step("lcfirst", () => { + assertEquals(Inflector.lcfirst('Hello world'), 'hello world'); + assertEquals(Inflector.lcfirst('Hello World'), 'hello World'); + }); + + await t.step("pascalize", () => { + assertEquals(Inflector.pascalize('hello-world'), 'Hello-world'); + assertEquals(Inflector.pascalize('hello_World'), 'HelloWorld'); + assertEquals(Inflector.pascalize('hello-world', '-'), 'HelloWorld'); + assertEquals(Inflector.pascalize('hello_World', '-'), 'Hello_World'); + }); + + await t.step("humanize", () => { + assertEquals(Inflector.humanize('hello-world'), 'Hello-world'); + assertEquals(Inflector.humanize('hello_World'), 'Hello World'); + assertEquals(Inflector.humanize('hello-world', '-'), 'Hello World'); + assertEquals(Inflector.humanize('hello_World', '-'), 'Hello_World'); + }); +}); From 3e9f4c02b6a9ddb91ac09e5591436a2234dc67b8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 20:04:29 +0200 Subject: [PATCH 028/379] Revert "Remove assignment" This reverts commit b003a65ae1594202c7bcb29923b914d1308a192e. --- discord/dispatchers/event.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/discord/dispatchers/event.ts b/discord/dispatchers/event.ts index 551a1ac0..4fd19ae3 100644 --- a/discord/dispatchers/event.ts +++ b/discord/dispatchers/event.ts @@ -112,7 +112,8 @@ export class EventDispatcher { const module = await import(`file:///${dir}/${file.name}`); // Make sure the file contains a valid handler - const eventName = Inflector.pascalize(file.name.replace('.ts', ''), '-'); + const name = file.name.replace('.ts', ''); + const eventName = Inflector.pascalize(name, '-'); const className = `${eventName}Event`; if(!(className in module)) { Logger.warning(`Could not find ${className} in "${file.name}", skipping...`); From 4901b91111fd514784016a4760df12fd8805ffe3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:05:04 +0200 Subject: [PATCH 029/379] Add Codecov action --- .github/workflows/codecov.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/codecov.yml diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 00000000..5da36a28 --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,12 @@ +name: Code Coverage + +on: + pull_request: + branches: [ master ] + +jobs: + test: + name: Code Coverage Report + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 10da1b6f57f6fcf9f59b56f66377cf92b893b55c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:18:11 +0200 Subject: [PATCH 030/379] Update codecov --- .github/workflows/codecov.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 5da36a28..8c0ad35c 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -6,7 +6,7 @@ on: jobs: test: - name: Code Coverage Report - uses: codecov/codecov-action@v3 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + - name: Code Coverage Report + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 29bc33e030ddd858c0157c5b7f5f0e67e9490d75 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:20:32 +0200 Subject: [PATCH 031/379] Update codecov --- .github/workflows/codecov.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 8c0ad35c..ffc8a328 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -1,12 +1,9 @@ name: Code Coverage - -on: - pull_request: - branches: [ master ] - +on: [push, pull_request] jobs: test: - - name: Code Coverage Report - uses: codecov/codecov-action@v3 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + steps: + - name: Code Coverage Report + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 646be6b912501501bdd80bbc6f6b77350a2a790a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:22:12 +0200 Subject: [PATCH 032/379] Update codecov --- .github/workflows/codecov.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index ffc8a328..533f90a1 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -2,6 +2,7 @@ name: Code Coverage on: [push, pull_request] jobs: test: + runs-on: ubuntu-latest steps: - name: Code Coverage Report uses: codecov/codecov-action@v3 From e875c4bcba9c2170c9686e9afaaf42bc4b07ed5a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:26:01 +0200 Subject: [PATCH 033/379] Update codecov --- .github/workflows/codecov.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 533f90a1..d0ccf220 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -8,3 +8,5 @@ jobs: uses: codecov/codecov-action@v3 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + gcov: true From ea015946f3f8312d0e112b6369b1357b7bcdede9 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:33:30 +0200 Subject: [PATCH 034/379] update codecov --- .github/workflows/codecov.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index d0ccf220..c055f714 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -4,9 +4,14 @@ jobs: test: runs-on: ubuntu-latest steps: - - name: Code Coverage Report + - uses: denolib/setup-deno@v1 + with: + deno-version: "1.30.0" + - name: Create coverage report + run: deno coverage ./coverage --lcov > coverage.lcov + - name: Upload Code Coverage Report uses: codecov/codecov-action@v3 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: - gcov: true + file: ./coverage.lcov From 5c5ba34adac32688faf154517c5d8c975080ccf5 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:34:17 +0200 Subject: [PATCH 035/379] Update codecov --- .github/workflows/codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index c055f714..01e1bb25 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -4,7 +4,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: denolib/setup-deno@v1 + - uses: denoland/setup-deno@v1 with: deno-version: "1.30.0" - name: Create coverage report From 515bbf22dcd7eb882380168445303ec4acf74315 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:40:08 +0200 Subject: [PATCH 036/379] Update codecov --- .github/workflows/codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 01e1bb25..cecb098b 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -14,4 +14,4 @@ jobs: env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: - file: ./coverage.lcov + files: coverage.lcov From 47192e24ffe168fe995087eb8e8a4addc75ff15c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:49:38 +0200 Subject: [PATCH 037/379] Update codecov --- .github/workflows/codecov.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index cecb098b..435e6b71 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -7,8 +7,10 @@ jobs: - uses: denoland/setup-deno@v1 with: deno-version: "1.30.0" - - name: Create coverage report - run: deno coverage ./coverage --lcov > coverage.lcov + - name: Run tests + run: deno test --allow-read --allow-env + - name: Generate lcov + run: deno coverage ./coverage/ --lcov --exclude="test\\.(ts|js)|wasm\\.js|testdata" > coverage.lcov - name: Upload Code Coverage Report uses: codecov/codecov-action@v3 env: From f32a4b071b6a2cf824a227a40c226af3c4a73584 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:51:04 +0200 Subject: [PATCH 038/379] Update codecov --- .github/workflows/codecov.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 435e6b71..b49d7803 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -4,7 +4,12 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: denoland/setup-deno@v1 + - name: Clone repository + uses: actions/checkout@v3 + with: + submodules: true + - name: Set up Deno + uses: denoland/setup-deno@v1 with: deno-version: "1.30.0" - name: Run tests From 21b3e779508d2592480ecca4dc7be57d7789b24b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Jul 2023 22:59:11 +0200 Subject: [PATCH 039/379] Update Codecov --- .github/workflows/codecov.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index b49d7803..1b1e6f92 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -13,9 +13,9 @@ jobs: with: deno-version: "1.30.0" - name: Run tests - run: deno test --allow-read --allow-env + run: deno test --coverage=./coverage --allow-read --allow-env - name: Generate lcov - run: deno coverage ./coverage/ --lcov --exclude="test\\.(ts|js)|wasm\\.js|testdata" > coverage.lcov + run: deno coverage ./coverage --lcov --exclude="test\\.(ts|js)|wasm\\.js|testdata" > coverage.lcov - name: Upload Code Coverage Report uses: codecov/codecov-action@v3 env: From 535c728f760e20abfc427ff6aea92eecb8bfe82d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 21 Jul 2023 12:13:21 +0200 Subject: [PATCH 040/379] Update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 379d3717..243c002c 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,11 @@ Someday I'll write a better usage guide. ## Compatibility Below a chart indicating for which Deno version this library is built and tested. -Compatibility may be more flexible, however, chances are this library may not work with older of newer versions than indicated. +Compatibility may be more flexible, however, chances are this library may not work with older or newer versions than indicated. | Library Version | Deno Version | |-----------------|--------------| +| main | 1.30.0 | | 1.1.0 | 1.24.0 | | 1.0.0 | 1.15.3 | | 0.0.2 | ??? | From 24ee5774683446c2dd0a323cf36622e19ce42f9e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 23 Jul 2023 15:28:44 +0200 Subject: [PATCH 041/379] Ignore getting data if not using HEAD --- communication/couchdb.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 0ad027c4..c4c63075 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -149,7 +149,8 @@ export class CouchDB { // Send our request and get the response const resp = await fetch(`${this.host}/${this.database}${endpoint}`, opts); - const data = await resp.json(); + let data = null; + if(opts.method !== 'HEAD') data = await resp.json(); // Prepare our CouchResponse const couchResponse = { From a1d4d7b2633fae038ec7d31e3165632a7b63bab6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 23 Jul 2023 15:35:27 +0200 Subject: [PATCH 042/379] Use GET instead of HEAD when upserting --- communication/couchdb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index c4c63075..47a83f4d 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -101,7 +101,7 @@ export class CouchDB { public async upsert(id: string, data: any): Promise { // Check if a document already exists // Insert a new document if not - const exists = await this.raw(id, null, { method: 'HEAD' }); + const exists = await this.raw(id, null, { method: 'GET' }); if(exists.status === 404) { data['_id'] = id; return await this.insert(data); From 9514c8d6dd07355faf6a4baf1624129974622a20 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 25 Jul 2023 18:28:48 +0200 Subject: [PATCH 043/379] Do not accept numbers (causes errors) --- communication/loki.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/loki.ts b/communication/loki.ts index a93d6188..7e27598d 100644 --- a/communication/loki.ts +++ b/communication/loki.ts @@ -2,7 +2,7 @@ import { Logger } from "../logging/logger.ts"; export interface LokiStream { stream: any; - values: Array>; + values: Array>; } export default class Loki { From e1ab58647f6c27c1a444bfdefdc5912b21de5da0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 25 Jul 2023 19:44:39 +0200 Subject: [PATCH 044/379] Do note use default --- communication/loki.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/loki.ts b/communication/loki.ts index 7e27598d..eb0bfb1f 100644 --- a/communication/loki.ts +++ b/communication/loki.ts @@ -5,7 +5,7 @@ export interface LokiStream { values: Array>; } -export default class Loki { +export class Loki { /** * @param host * @param tenant Tenant ID to use for the log item. Can be ommitted if not using multi-tenant mode. From 14443afbca25c7045a3ebc11abc7de3aaf575064 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 13:27:34 +0200 Subject: [PATCH 045/379] Cache imports and return error responses if something goes wrong --- webserver/routing/router.ts | 66 ++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 8675164e..6196e140 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -1,11 +1,13 @@ import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts"; import { pathToRegexp } from "../pathToRegexp.ts"; +import { Inflector } from "../../util/inflector.ts"; +import { Logger } from "../../logging/logger.ts"; interface Route { path: string; controller: string; action: string; - method: string; + method?: string; } export interface RouteArgs { @@ -18,6 +20,7 @@ export interface RouteArgs { export class Router { private static routes: Route[] = []; public static getRoutes() { return Router.routes; } + private static _cache = {}; /** * Match the controller and action to a route @@ -58,20 +61,49 @@ export class Router { // Make sure a route was specified if(args.route === null) return null; - // Import the controller file - const imported = await import(`file://${Deno.cwd()}/src/controller/${args.route.controller[0].toLowerCase() + args.route.controller.slice(1)}.controller.ts`); - - // Instantiate the controller - const controller = new imported[`${args.route.controller}Controller`](args.route.controller, args.route.action); - - // Execute our action - await controller[args.route.action](args); - - // Render the body - await controller.render(); - - // Return our response - return controller.response(); + // Import and cache controller file if need be + if(!(args.route.controller in Router._cache)) { + try { + Router._cache[args.route.controller] = await import(`file://${Deno.cwd()}/src/controller/${Inflector.lcfirst(args.route.controller)}.controller.ts`); + } catch(e) { + Logger.error(`Could not import "${args.route.controller}": ${e.message}`, e.stack); + return new Response( + 'Internal Server Error', + { + status: 500, + headers: { + 'content-type': 'text/plain' + } + } + ); + } + } + + + try { + // Instantiate the controller + const controller = new Router._cache[args.route.controller][`${args.route.controller}Controller`](args.route.controller, args.route.action); + + // Execute our action + await controller[args.route.action](args); + + // Render the body + await controller.render(); + + // Return our response + return controller.response(); + } catch(e) { + Logger.error(`Could not execute "${args.route.controller}": ${e.message}`. e.stack); + return new Response( + 'Internal Server Error', + { + status: 500, + headers: { + 'content-type': 'text/plain' + } + } + ); + } } /** @@ -122,12 +154,14 @@ export class Router { } /** - * Add a route + * Add a route. + * Defaults to 'GET' * * @param route * @returns void */ public static add(route: Route): void { + if(!('method' in route)) route.method = 'GET'; Router.routes.push(route); } } From cb3d440cac166bcdf85646d642f85a7d2a50feda Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 13:29:09 +0200 Subject: [PATCH 046/379] Add comment --- webserver/routing/router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 6196e140..797ab08b 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -79,7 +79,7 @@ export class Router { } } - + // Run our controller try { // Instantiate the controller const controller = new Router._cache[args.route.controller][`${args.route.controller}Controller`](args.route.controller, args.route.action); From 0738b720da53e2b77d945a297e92607699b441a6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 19:21:32 +0200 Subject: [PATCH 047/379] Export websocket --- websocket/mod.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/websocket/mod.ts b/websocket/mod.ts index c162a2da..c3bc65ea 100644 --- a/websocket/mod.ts +++ b/websocket/mod.ts @@ -1,2 +1,3 @@ export * from "./authenticator.ts"; export * from "./events.ts"; +export * from "./websocket.ts"; From 239f01fa1c4cba5c7ca737003119201d52ea1fc3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 19:24:05 +0200 Subject: [PATCH 048/379] Remove async and await from route --- webserver/routing/router.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 797ab08b..2ea0d9ac 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -27,7 +27,7 @@ export class Router { * * @param request */ - public async route(request: Request) { + public route(request: Request) { // Get the request path minus the domain const host = request.headers.get("host"); let path = request.url @@ -39,7 +39,7 @@ export class Router { // Check if it is the right method // Check if it's the right path // Return the route if route found - for await(let route of Router.routes) { + for (const route of Router.routes) { if(route.method !== request.method) continue; // Make sure we have a matching route From b0a292cd3ee97a7bf0bb34a2bbc696db69de6824 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 19:24:36 +0200 Subject: [PATCH 049/379] Fix bug with 404 not being sent when route wasn't found --- webserver/webserver.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/webserver/webserver.ts b/webserver/webserver.ts index 5ec9ce7b..204147a4 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -28,9 +28,9 @@ export class Webserver { for await(const request of httpConn) { Logger.debug(`Request from "${(conn.remoteAddr as Deno.NetAddr).hostname!}:${(conn.remoteAddr as Deno.NetAddr).port!}": ${request.request.method} | ${request.request.url}`); try { - const routing = await this.router.route(request.request); + const routing = this.router.route(request.request); if(!routing || !routing.route) { - return new Response( + await request.respondWith(new Response( 'The requested page could not be found.', { status: 404, @@ -39,7 +39,8 @@ export class Webserver { 'Access-Control-Allow-Origin': '*' } } - ); + )); + return; } const response = await this.router.execute({ route: routing.route, From 9002422da8131af4b2a24bc116f7f49697e127e3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 19:30:58 +0200 Subject: [PATCH 050/379] Add comments and clean up a wee bit --- webserver/webserver.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/webserver/webserver.ts b/webserver/webserver.ts index 204147a4..e39fe14b 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -3,11 +3,11 @@ import { Router } from "./routing/router.ts"; export class Webserver { private server: any = null; - private port: number = 0; private router: Router = new Router(); - constructor(port: number = 80) { - this.port = port; + constructor( + private readonly port: number = 80 + ) { } public async start() { @@ -16,6 +16,7 @@ export class Webserver { // Serve connections for await (const conn of this.server) { + // @ts-ignore Left intentionally without await this.serve(conn); } } @@ -28,6 +29,8 @@ export class Webserver { for await(const request of httpConn) { Logger.debug(`Request from "${(conn.remoteAddr as Deno.NetAddr).hostname!}:${(conn.remoteAddr as Deno.NetAddr).port!}": ${request.request.method} | ${request.request.url}`); try { + // Try to find a matching route + // Respond with 404 if not found const routing = this.router.route(request.request); if(!routing || !routing.route) { await request.respondWith(new Response( @@ -42,13 +45,19 @@ export class Webserver { )); return; } + + // Execute the route const response = await this.router.execute({ route: routing.route, body: await this.router.getBody(request.request), params: await this.router.getParams(routing.route, routing.path ?? '/'), auth: this.router.getAuth(request.request) }); + + // Check if the response was empty or not if(!response) throw Error('Response was empty'); + + // Send our response await request.respondWith(response); } catch(e) { Logger.error(`Could not serve response: ${e.message}`, e.stack); From d20a500b029774da2bd284879a747a40e7b7b755 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 19:31:38 +0200 Subject: [PATCH 051/379] Fix typo --- webserver/routing/router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 2ea0d9ac..a366f701 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -93,7 +93,7 @@ export class Router { // Return our response return controller.response(); } catch(e) { - Logger.error(`Could not execute "${args.route.controller}": ${e.message}`. e.stack); + Logger.error(`Could not execute "${args.route.controller}": ${e.message}`, e.stack); return new Response( 'Internal Server Error', { From c330df9248036979abb852ce7bc78465fb4a502f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 19:56:52 +0200 Subject: [PATCH 052/379] Move type to its own class --- webserver/controller/controller.ts | 20 ++++++++++++++------ webserver/http/headers.ts | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 webserver/http/headers.ts diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 8b4a23c2..4f926367 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -1,13 +1,24 @@ import { handlebarsEngine } from "https://raw.githubusercontent.com/FinlayDaG33k/view-engine/patch-1/mod.ts"; import { Logger } from "../../logging/logger.ts"; +import { Headers } from "../http/headers.ts"; export class Controller { + protected headers: Headers = new Headers(); protected name = '' protected action = ''; protected vars: any = {}; protected status = 200; protected body = ''; - protected type = 'text/html'; + + /** + * + * @deprecated Please use "Controller.headers.set()" instead. + * @param value + */ + public set type(value: string = 'text/html') { + Logger.warning('Setting type on controller itself is deprecated, please use "Controller.headers.set()" instead.'); + this.headers.set('Content-Type', value); + } constructor( name: string, @@ -32,7 +43,7 @@ export class Controller { * @returns Promise */ public async render(): Promise { - switch(this.type) { + switch(this.headers.get('Content-Type').toLowerCase()) { case 'application/json': this.body = JSON.stringify(this.vars['data']); break; @@ -74,10 +85,7 @@ export class Controller { this.body, { status: this.status, - headers: { - 'content-type': this.type, - 'Access-Control-Allow-Origin': '*' - } + headers: this.headers.get(), } ); } diff --git a/webserver/http/headers.ts b/webserver/http/headers.ts new file mode 100644 index 00000000..64a903a0 --- /dev/null +++ b/webserver/http/headers.ts @@ -0,0 +1,20 @@ +export class Headers { + private _headers = { + 'Content-Type': 'text/html', + }; + + public get(key: string|null = null): any { + if(key) return this._headers[key]; + return this._headers; + } + + /** + * Set a response header + * + * @param key + * @param value + */ + public set(key: string, value: string) { + this._headers[key] = value; + } +} From 33c90998a225707fdb5d6918357eed4c9c8220a0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 19:57:08 +0200 Subject: [PATCH 053/379] Do not set CORS to '*' you moron --- webserver/webserver.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webserver/webserver.ts b/webserver/webserver.ts index e39fe14b..c166dd6c 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -38,8 +38,7 @@ export class Webserver { { status: 404, headers: { - 'content-type': 'text/plain', - 'Access-Control-Allow-Origin': '*' + 'content-type': 'text/plain' } } )); From b5c7b3d6832e765e3bd94b42220c2ab374605b7f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 20:09:00 +0200 Subject: [PATCH 054/379] Cleanup setter --- webserver/controller/controller.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 4f926367..4c835139 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -4,8 +4,6 @@ import { Headers } from "../http/headers.ts"; export class Controller { protected headers: Headers = new Headers(); - protected name = '' - protected action = ''; protected vars: any = {}; protected status = 200; protected body = ''; @@ -21,11 +19,9 @@ export class Controller { } constructor( - name: string, - action: string = 'index' + protected readonly name: string, + protected readonly action: string = 'index', ) { - this.name = name; - this.action = action; } /** From 9caf34f02676d215ff949f078224ae8829c346b3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 20:12:48 +0200 Subject: [PATCH 055/379] Some consistency --- webserver/routing/router.ts | 4 ++-- webserver/webserver.ts | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index a366f701..53bd7ea6 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -95,11 +95,11 @@ export class Router { } catch(e) { Logger.error(`Could not execute "${args.route.controller}": ${e.message}`, e.stack); return new Response( - 'Internal Server Error', + 'An Internal Server Error Occurred', { status: 500, headers: { - 'content-type': 'text/plain' + 'Content-Type': 'text/plain' } } ); diff --git a/webserver/webserver.ts b/webserver/webserver.ts index c166dd6c..d3df06a3 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -38,7 +38,7 @@ export class Webserver { { status: 404, headers: { - 'content-type': 'text/plain' + 'Content-Type': 'text/plain' } } )); @@ -60,7 +60,15 @@ export class Webserver { await request.respondWith(response); } catch(e) { Logger.error(`Could not serve response: ${e.message}`, e.stack); - await request.respondWith(new Response('Internal server error', {status: 500})); + await request.respondWith(new Response( + 'An Internal Server Error Occurred', + { + status: 500, + headers: { + 'Content-Type': 'text/plain' + } + } + )); } } } From e950f6f37735e639dc6397af8d3ca13843a76022 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 20:39:05 +0200 Subject: [PATCH 056/379] Add enum with all status codes --- webserver/controller/controller.ts | 3 +- webserver/http/status-codes.ts | 69 ++++++++++++++++++++++++++++++ webserver/webserver.ts | 5 ++- 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 webserver/http/status-codes.ts diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 4c835139..b7463342 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -1,11 +1,12 @@ import { handlebarsEngine } from "https://raw.githubusercontent.com/FinlayDaG33k/view-engine/patch-1/mod.ts"; import { Logger } from "../../logging/logger.ts"; import { Headers } from "../http/headers.ts"; +import { StatusCodes } from "../http/status-codes.ts"; export class Controller { protected headers: Headers = new Headers(); protected vars: any = {}; - protected status = 200; + protected status: StatusCodes = StatusCodes.OK; protected body = ''; /** diff --git a/webserver/http/status-codes.ts b/webserver/http/status-codes.ts new file mode 100644 index 00000000..ddbe5029 --- /dev/null +++ b/webserver/http/status-codes.ts @@ -0,0 +1,69 @@ +export enum StatusCodes { + CONTINUE = 100, + SWITCHING_PROTOCOLS = 101, + PROCESSING = 102, + EARLY_HINTS = 103, + + OK = 200, + CREATED = 201, + ACCEPTED = 202, + NON_AUTHORATIVE_INFORMATION = 203, + NO_CONTENT = 204, + RESET_CONTENT = 205, + PARTIAL_CONTENT = 206, + MULTI_STATUS = 207, + ALREADY_REPORTED = 208, + IM_USED = 226, + + MULTIPLE_CHOICES = 300, + MOVED_PERMANENTLY = 301, + FOUND = 302, + SEE_OTHER = 303, + NOT_MODIFIED = 304, + USE_PROXY = 305, + UNUSED = 306, + TEMPORARY_REDIRECT = 307, + PERMANENT_REDIRECT = 308, + + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + PAYMENT_REQUIRED = 402, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + NOT_ACCEPTABLE = 406, + PROXY_AUTHENTICATION_REQUIRED = 407, + REQUEST_TIMEOUT = 408, + CONFLICT = 409, + GONE = 410, + LENGTH_REQUIRED = 411, + PRECONDITION_FAILED = 412, + PAYLOAD_TOO_LARGE = 413, + URI_TOO_LONG = 414, + UNSUPPORTED_MEDIA_TYPE = 415, + RANGE_NOT_SATISFIABLE = 416, + EXPECTATION_FAILED = 417, + IM_A_TEAPOT = 418, + MISDIRECTED_REQUEST = 421, + UNPROCESSABLE_CONTENT = 422, + LOCKED = 423, + FAILED_DEPENDENCY = 424, + TOO_EARLY = 425, + UPGRADE_REQUIRED = 426, + PRECONDITION_REQUIRED = 428, + TOO_MANY_REQUESTS = 429, + REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + UNAVAILABLE_FOR_LEGAL_REASONS = 451, + + INTERNAL_SERVER_ERROR = 500, + NOT_IMPLEMENTED = 501, + BAD_GATEWAY = 502, + SERVICE_UNAVAILABLE = 503, + GATEWAY_TIMEOUT = 504, + HTTP_VERSION_NOT_SUPPORTED = 505, + VARIANT_ALSO_NEGOTIATED = 506, + INSUFFICIENT_STORAGE = 507, + LOOP_DETECTED = 508, + NOT_EXTENDED = 510, + NETWORK_AUTHENTICATION_REQUIRED = 511 +} diff --git a/webserver/webserver.ts b/webserver/webserver.ts index d3df06a3..1c866944 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -1,5 +1,6 @@ import { Logger } from "../logging/logger.ts"; import { Router } from "./routing/router.ts"; +import { StatusCodes } from "./http/status-codes.ts"; export class Webserver { private server: any = null; @@ -36,7 +37,7 @@ export class Webserver { await request.respondWith(new Response( 'The requested page could not be found.', { - status: 404, + status: StatusCodes.NOT_FOUND, headers: { 'Content-Type': 'text/plain' } @@ -63,7 +64,7 @@ export class Webserver { await request.respondWith(new Response( 'An Internal Server Error Occurred', { - status: 500, + status: StatusCodes.INTERNAL_SERVER_ERROR, headers: { 'Content-Type': 'text/plain' } From c137f7de8e6255095cbb65d7c5120d9ea42e8ffe Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 20:39:39 +0200 Subject: [PATCH 057/379] Create mod files --- webserver/http/mod.ts | 2 ++ webserver/mod.ts | 1 + 2 files changed, 3 insertions(+) create mode 100644 webserver/http/mod.ts diff --git a/webserver/http/mod.ts b/webserver/http/mod.ts new file mode 100644 index 00000000..357d15d0 --- /dev/null +++ b/webserver/http/mod.ts @@ -0,0 +1,2 @@ +export * from "./headers.ts"; +export * from "./status-codes.ts"; diff --git a/webserver/mod.ts b/webserver/mod.ts index 43981f43..265235a2 100644 --- a/webserver/mod.ts +++ b/webserver/mod.ts @@ -1,3 +1,4 @@ export * from "./controller/mod.ts"; +export * from "./http/mod.ts"; export * from "./routing/mod.ts"; export * from "./webserver.ts"; From 3b6cd06b7536e5946fa6e5a74911dd3e04b5ac11 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 20:44:05 +0200 Subject: [PATCH 058/379] Cleanup template directory handling --- webserver/controller/controller.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index b7463342..1786c1b9 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -2,8 +2,10 @@ import { handlebarsEngine } from "https://raw.githubusercontent.com/FinlayDaG33k import { Logger } from "../../logging/logger.ts"; import { Headers } from "../http/headers.ts"; import { StatusCodes } from "../http/status-codes.ts"; +import { Inflector } from "../../util/inflector.ts"; export class Controller { + protected readonly _templateDir = './src/templates'; protected headers: Headers = new Headers(); protected vars: any = {}; protected status: StatusCodes = StatusCodes.OK; @@ -60,18 +62,18 @@ export class Controller { */ private async handlebars(): Promise { // Get our template location - const path = `./src/templates/${this.name[0].toLowerCase() + this.name.slice(1)}/${this.action}.hbs`; + const path = `${this._templateDir}/${Inflector.lcfirst(this.name)}/${this.action}.hbs`; // Make sure out template exists try { await Deno.stat(path); } catch(e) { - Logger.error(`Could not find template for "${this.name[0].toLowerCase() + this.name.slice(1)}#${this.action}"`, e.stack); + Logger.error(`Could not find template for "${Inflector.lcfirst(this.name)}#${this.action}"`, e.stack); return; } // Read our template - const template = await Deno.readTextFile(`./src/templates/${this.name[0].toLowerCase() + this.name.slice(1)}/${this.action}.hbs`); + const template = await Deno.readTextFile(`${this._templateDir}/${Inflector.lcfirst(this.name)}/${this.action}.hbs`); // Let the engine render return handlebarsEngine(template, this.vars); From 49be2f167851d0407de69d0702e246147f4038d3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 20:46:27 +0200 Subject: [PATCH 059/379] Clean up controller dir path --- webserver/controller/controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 1786c1b9..692c4e1f 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -5,7 +5,7 @@ import { StatusCodes } from "../http/status-codes.ts"; import { Inflector } from "../../util/inflector.ts"; export class Controller { - protected readonly _templateDir = './src/templates'; + protected readonly _templateDir = `file://${Deno.cwd()}/src/templates`; protected headers: Headers = new Headers(); protected vars: any = {}; protected status: StatusCodes = StatusCodes.OK; From f5fba39c716d3af30c2ba49ca446ce97ee793167 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 20:46:34 +0200 Subject: [PATCH 060/379] Use Deno CWD --- webserver/routing/router.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 53bd7ea6..4e0271c3 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -18,6 +18,7 @@ export interface RouteArgs { } export class Router { + private static readonly _controllerDir = `file://${Deno.cwd()}/src/controller`; private static routes: Route[] = []; public static getRoutes() { return Router.routes; } private static _cache = {}; @@ -64,7 +65,7 @@ export class Router { // Import and cache controller file if need be if(!(args.route.controller in Router._cache)) { try { - Router._cache[args.route.controller] = await import(`file://${Deno.cwd()}/src/controller/${Inflector.lcfirst(args.route.controller)}.controller.ts`); + Router._cache[args.route.controller] = await import(`${Router._controllerDir}/${Inflector.lcfirst(args.route.controller)}.controller.ts`); } catch(e) { Logger.error(`Could not import "${args.route.controller}": ${e.message}`, e.stack); return new Response( From 872a1c6f8dd48b3367387ece96e6062c57f9bca4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Jul 2023 21:01:31 +0200 Subject: [PATCH 061/379] Add class for GraphQL queries --- communication/graphql.ts | 47 ++++++++++++++++++++++++++++++++++++++++ communication/mod.ts | 1 + 2 files changed, 48 insertions(+) create mode 100644 communication/graphql.ts diff --git a/communication/graphql.ts b/communication/graphql.ts new file mode 100644 index 00000000..df2ff599 --- /dev/null +++ b/communication/graphql.ts @@ -0,0 +1,47 @@ +export class GraphQL { + private _variables = {}; + private _query: string = 'query{}'; + + public constructor( + private readonly endpoint = '/graphql' + ) { + } + + public execute() { + return fetch(this.endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + body: JSON.stringify({ + query: this._query, + variables: this._variables + }) + }).then(r => r.json()); + } + + /** + * Set our query string + * + * @param query + * @return The instance of this class + */ + + public setQuery(query: string): GraphQL { + this._query = query; + return this; + } + + /** + * Add a variable to our variables object + * + * @param key + * @param value + * @return The instance of this class + */ + public addVariable(key: string, value: string): GraphQL { + this._variables[key] = value; + return this; + } +} diff --git a/communication/mod.ts b/communication/mod.ts index 2a2d8e82..bdef1d50 100644 --- a/communication/mod.ts +++ b/communication/mod.ts @@ -1,5 +1,6 @@ export * from "./couchdb.ts"; export * from "./druid.ts"; +export * from "./graphql.ts"; export * from "./loki.ts"; export * from "./ntfy.ts"; export * from "./rcon.ts"; From d2924ca1c955dd23f82e522080d6799f8ae4d1d2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 17:45:48 +0200 Subject: [PATCH 062/379] Add utility function to raise errors --- util/mod.ts | 1 + util/raise.ts | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 util/raise.ts diff --git a/util/mod.ts b/util/mod.ts index 2972944d..2a1e0afb 100644 --- a/util/mod.ts +++ b/util/mod.ts @@ -3,6 +3,7 @@ export * from "./folder-exists.ts"; export * from "./inflector.ts"; export * from "./is-ts.ts"; export * from "./lcfirst.ts"; +export * from "./raise.ts"; export * from "./time-string.ts"; export * from "./tokenizer.ts"; export * from "./ucfirst.ts"; diff --git a/util/raise.ts b/util/raise.ts new file mode 100644 index 00000000..e36f3a30 --- /dev/null +++ b/util/raise.ts @@ -0,0 +1,8 @@ +/** + * Utility function that literally just throws an error + * + * @param err + */ +export function raise(err: string): never { + throw new Error(err); +} From d72f2d2c09cc4ea12162082a5cc9832cef19fd94 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 17:46:21 +0200 Subject: [PATCH 063/379] Split handlebars renderer and update controller a bit --- webserver/controller/controller.ts | 31 ++++--------------------- webserver/renderers/handlebars.ts | 37 ++++++++++++++++++++++++++++++ webserver/renderers/mod.ts | 1 + 3 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 webserver/renderers/handlebars.ts create mode 100644 webserver/renderers/mod.ts diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 692c4e1f..87bd65ed 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -1,17 +1,18 @@ -import { handlebarsEngine } from "https://raw.githubusercontent.com/FinlayDaG33k/view-engine/patch-1/mod.ts"; import { Logger } from "../../logging/logger.ts"; import { Headers } from "../http/headers.ts"; import { StatusCodes } from "../http/status-codes.ts"; import { Inflector } from "../../util/inflector.ts"; +import { Handlebars } from "../renderers/handlebars.ts"; export class Controller { - protected readonly _templateDir = `file://${Deno.cwd()}/src/templates`; + protected static readonly _templateDir = `file://${Deno.cwd()}/src/templates`; protected headers: Headers = new Headers(); protected vars: any = {}; protected status: StatusCodes = StatusCodes.OK; protected body = ''; /** + * Set the 'Content-Type' header * * @deprecated Please use "Controller.headers.set()" instead. * @param value @@ -51,34 +52,10 @@ export class Controller { break; case 'text/html': default: - this.body = await this.handlebars(); + this.body = await Handlebars.render(`${Controller._templateDir}/${Inflector.lcfirst(this.name)}/${this.action}.hbs`, this.vars) ?? ''; } } - /** - * Render Handlebars templates - * - * @returns Promise - */ - private async handlebars(): Promise { - // Get our template location - const path = `${this._templateDir}/${Inflector.lcfirst(this.name)}/${this.action}.hbs`; - - // Make sure out template exists - try { - await Deno.stat(path); - } catch(e) { - Logger.error(`Could not find template for "${Inflector.lcfirst(this.name)}#${this.action}"`, e.stack); - return; - } - - // Read our template - const template = await Deno.readTextFile(`${this._templateDir}/${Inflector.lcfirst(this.name)}/${this.action}.hbs`); - - // Let the engine render - return handlebarsEngine(template, this.vars); - } - public response() { return new Response( this.body, diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts new file mode 100644 index 00000000..e1c3bd6e --- /dev/null +++ b/webserver/renderers/handlebars.ts @@ -0,0 +1,37 @@ +import { handlebarsEngine } from "https://raw.githubusercontent.com/FinlayDaG33k/view-engine/patch-1/mod.ts"; +import { Logger } from "../../logging/logger.ts"; +import { raise } from "../../util/raise.ts"; + +export class Handlebars { + private static _cache = {}; + + public static async render(path: string, vars: any = {}, cache = true): Promise { + // Load our template + const template = await Handlebars.getTemplate(path, cache) ?? raise('Could not load template'); + + // Let the engine render + return handlebarsEngine(template, vars); + } + + private static async getTemplate(path: string, cache: boolean): Promise { + // Read template from cache if possible + if(cache && path in Handlebars._cache) return Handlebars._cache[path]; + + // Make sure out template exists + try { + await Deno.stat(path); + } catch(e) { + Logger.error(`Could not render handlebars template: Could not read template at "${path}"`, e.stack); + return; + } + + // Read our template + const template = await Deno.readTextFile(path); + + // Write to cache if need be + if(cache) Handlebars._cache[path] = template; + + // Return the template + return template; + } +} diff --git a/webserver/renderers/mod.ts b/webserver/renderers/mod.ts new file mode 100644 index 00000000..00d63ff9 --- /dev/null +++ b/webserver/renderers/mod.ts @@ -0,0 +1 @@ +export * from "./handlebars.ts"; From 2d6ce69291178804aba3540fdefb4e4ea8f40188 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 17:55:11 +0200 Subject: [PATCH 064/379] Wrap return time in boolean --- util/folder-exists.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/folder-exists.ts b/util/folder-exists.ts index bc069df4..fe79b389 100644 --- a/util/folder-exists.ts +++ b/util/folder-exists.ts @@ -1,4 +1,4 @@ -export async function folderExists(path: string): boolean { +export async function folderExists(path: string): Promise { try { const target = await Deno.stat(path); return target.isDirectory; From 3b431ef24015ed71b2b6d201d226639c6a5491cd Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 19:07:26 +0200 Subject: [PATCH 065/379] Create ResponseBuilder and put it in charge of managing headers as well --- webserver/controller/controller.ts | 30 +++----- webserver/http/headers.ts | 20 ----- webserver/http/mod.ts | 2 +- webserver/http/response-builder.ts | 120 +++++++++++++++++++++++++++++ webserver/routing/router.ts | 2 +- 5 files changed, 131 insertions(+), 43 deletions(-) delete mode 100644 webserver/http/headers.ts create mode 100644 webserver/http/response-builder.ts diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 87bd65ed..b804e12e 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -1,15 +1,12 @@ import { Logger } from "../../logging/logger.ts"; -import { Headers } from "../http/headers.ts"; -import { StatusCodes } from "../http/status-codes.ts"; import { Inflector } from "../../util/inflector.ts"; import { Handlebars } from "../renderers/handlebars.ts"; +import { ResponseBuilder } from "../http/response-builder.ts"; export class Controller { protected static readonly _templateDir = `file://${Deno.cwd()}/src/templates`; - protected headers: Headers = new Headers(); + protected response: ResponseBuilder = new ResponseBuilder(); protected vars: any = {}; - protected status: StatusCodes = StatusCodes.OK; - protected body = ''; /** * Set the 'Content-Type' header @@ -17,9 +14,9 @@ export class Controller { * @deprecated Please use "Controller.headers.set()" instead. * @param value */ - public set type(value: string = 'text/html') { + public set type(value = 'text/html') { Logger.warning('Setting type on controller itself is deprecated, please use "Controller.headers.set()" instead.'); - this.headers.set('Content-Type', value); + this.response.withHeader('Content-Type', value); } constructor( @@ -43,26 +40,17 @@ export class Controller { * @returns Promise */ public async render(): Promise { - switch(this.headers.get('Content-Type').toLowerCase()) { + switch(this.response.getHeaderLine('Content-Type').toLowerCase()) { case 'application/json': - this.body = JSON.stringify(this.vars['data']); + this.response.withBody(JSON.stringify(this.vars['data'])); break; case 'text/plain': - this.body = this.vars['message']; + this.response.withBody(this.vars['message']); break; case 'text/html': default: - this.body = await Handlebars.render(`${Controller._templateDir}/${Inflector.lcfirst(this.name)}/${this.action}.hbs`, this.vars) ?? ''; + const body = await Handlebars.render(`${Controller._templateDir}/${Inflector.lcfirst(this.name)}/${this.action}.hbs`, this.vars) ?? ''; + this.response.withBody(body); } } - - public response() { - return new Response( - this.body, - { - status: this.status, - headers: this.headers.get(), - } - ); - } } diff --git a/webserver/http/headers.ts b/webserver/http/headers.ts deleted file mode 100644 index 64a903a0..00000000 --- a/webserver/http/headers.ts +++ /dev/null @@ -1,20 +0,0 @@ -export class Headers { - private _headers = { - 'Content-Type': 'text/html', - }; - - public get(key: string|null = null): any { - if(key) return this._headers[key]; - return this._headers; - } - - /** - * Set a response header - * - * @param key - * @param value - */ - public set(key: string, value: string) { - this._headers[key] = value; - } -} diff --git a/webserver/http/mod.ts b/webserver/http/mod.ts index 357d15d0..f0d83399 100644 --- a/webserver/http/mod.ts +++ b/webserver/http/mod.ts @@ -1,2 +1,2 @@ -export * from "./headers.ts"; +export * from "./response-builder.ts"; export * from "./status-codes.ts"; diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts new file mode 100644 index 00000000..89966063 --- /dev/null +++ b/webserver/http/response-builder.ts @@ -0,0 +1,120 @@ +import { StatusCodes } from "./status-codes.ts"; + +export class ResponseBuilder { + private readonly _headers: Map> = new Map>(); + private _status = StatusCodes.OK; + private _body: string = ''; + + public constructor() { + // Set default headers + this.withHeader('Content-Type', 'text/html'); + } + + /** + * Get all headers we've set. + */ + public getHeaders(): typeof this._headers { + return this._headers; + } + + /** + * Get a header as an array. + * Use ResponseBuilder.getHeaderLine() if wanted as a string instead. + * + * @param name + */ + public getHeader(name: string): string[] { + return this._headers.get(name) ?? []; + } + + /** + * Get a header as a string. + * + * @param name + */ + public getHeaderLine(name: string): string { + const header = this.getHeader(name); + return header.join(', '); + } + + /** + * Check if a header is set. + * + * @param name + */ + public hasHeader(name: string): boolean { + return this._headers.has(name); + } + + /** + * Set a header, overriding the old value. + * Use ResponseBuilder.withAddedHeader() if you want to set multiple values. + * + * @param name + * @param value + */ + public withHeader(name: string, value: string): ResponseBuilder { + this._headers.set(name, [value]); + return this; + } + + /** + * Add a value to our headers. + * Use ResponseBuilder.withHeader() if you want to override it instead. + * + * @param name + * @param value + */ + public withAddedHeader(name: string, value: string): ResponseBuilder { + // Check if we have existing headers + // If not, start with an empty array + const existing = this._headers.get(name) ?? []; + + // Add our value + existing.push(value); + + // Save our header + this._headers.set(name, existing); + + // Return this route builder + return this; + } + + /** + * Set our response status. + * + * @param status + */ + public withStatus(status: StatusCodes = StatusCodes.OK): ResponseBuilder { + this._status = status; + return this; + } + + /** + * Set our response body. + * + * @param body + */ + public withBody(body: string): ResponseBuilder { + this._body = body; + return this; + } + + /** + * Build our final response that can be sent back to the client. + */ + public build(): Response { + const headers: any = {}; + for(const [name, value] of this.getHeaders()) { + headers[name] = value; + } + + return new Response( + this._body, + { + status: this._status, + headers: headers, + } + ); + } +} diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 4e0271c3..c6bdceab 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -92,7 +92,7 @@ export class Router { await controller.render(); // Return our response - return controller.response(); + return controller.response.build(); } catch(e) { Logger.error(`Could not execute "${args.route.controller}": ${e.message}`, e.stack); return new Response( From 2764a3f997f295debd00aadf167a0aef67b99de8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 19:08:48 +0200 Subject: [PATCH 066/379] Update comment --- webserver/controller/controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index b804e12e..43c4870e 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -11,7 +11,7 @@ export class Controller { /** * Set the 'Content-Type' header * - * @deprecated Please use "Controller.headers.set()" instead. + * @deprecated Please use "Controller.response.withHeader()" instead. * @param value */ public set type(value = 'text/html') { From c4f8436d4ab516c00b3de9d0f13af7c4dca52386 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 19:23:51 +0200 Subject: [PATCH 067/379] Use a Request object to pass data to the controller more easily --- webserver/controller/controller.ts | 4 ++-- webserver/http/mod.ts | 1 + webserver/http/request.ts | 8 ++++++++ webserver/routing/router.ts | 8 ++++++-- 4 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 webserver/http/request.ts diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 43c4870e..002ba17e 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -2,6 +2,7 @@ import { Logger } from "../../logging/logger.ts"; import { Inflector } from "../../util/inflector.ts"; import { Handlebars } from "../renderers/handlebars.ts"; import { ResponseBuilder } from "../http/response-builder.ts"; +import { Request } from "../http/request.ts"; export class Controller { protected static readonly _templateDir = `file://${Deno.cwd()}/src/templates`; @@ -20,8 +21,7 @@ export class Controller { } constructor( - protected readonly name: string, - protected readonly action: string = 'index', + protected readonly request: Request, ) { } diff --git a/webserver/http/mod.ts b/webserver/http/mod.ts index f0d83399..19c54a6d 100644 --- a/webserver/http/mod.ts +++ b/webserver/http/mod.ts @@ -1,2 +1,3 @@ +export * from "./request.ts"; export * from "./response-builder.ts"; export * from "./status-codes.ts"; diff --git a/webserver/http/request.ts b/webserver/http/request.ts new file mode 100644 index 00000000..7f4f1ea3 --- /dev/null +++ b/webserver/http/request.ts @@ -0,0 +1,8 @@ +import { RouteArgs } from "../routing/router.ts"; + +export class Request { + constructor( + private readonly args: RouteArgs + ) { + } +} diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index c6bdceab..a2065165 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -2,6 +2,7 @@ import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts" import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../util/inflector.ts"; import { Logger } from "../../logging/logger.ts"; +import { Request } from "../http/request.ts"; interface Route { path: string; @@ -82,11 +83,14 @@ export class Router { // Run our controller try { + // Create our Request object + const req = new Request(args); + // Instantiate the controller - const controller = new Router._cache[args.route.controller][`${args.route.controller}Controller`](args.route.controller, args.route.action); + const controller = new Router._cache[args.route.controller][`${args.route.controller}Controller`](req); // Execute our action - await controller[args.route.action](args); + await controller[args.route.action](); // Render the body await controller.render(); From 9f34dbcde2a7d8a18979aec426c703cc6a19e031 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 19:24:22 +0200 Subject: [PATCH 068/379] Remove useless assigment --- webserver/routing/router.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index a2065165..89990dbf 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -83,11 +83,8 @@ export class Router { // Run our controller try { - // Create our Request object - const req = new Request(args); - // Instantiate the controller - const controller = new Router._cache[args.route.controller][`${args.route.controller}Controller`](req); + const controller = new Router._cache[args.route.controller][`${args.route.controller}Controller`](new Request(args)); // Execute our action await controller[args.route.action](); From fe88e05650a9ec77d479436f969e77bddd05fca8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 19:27:02 +0200 Subject: [PATCH 069/379] Fix a small naming conflict --- webserver/routing/router.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 89990dbf..53779131 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -2,7 +2,7 @@ import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts" import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../util/inflector.ts"; import { Logger } from "../../logging/logger.ts"; -import { Request } from "../http/request.ts"; +import { Request as ChompRequest } from "../http/request.ts"; interface Route { path: string; @@ -84,7 +84,7 @@ export class Router { // Run our controller try { // Instantiate the controller - const controller = new Router._cache[args.route.controller][`${args.route.controller}Controller`](new Request(args)); + const controller = new Router._cache[args.route.controller][`${args.route.controller}Controller`](new ChompRequest(args)); // Execute our action await controller[args.route.action](); From 62064a1495df7f5978adae774b1e9f33c39aaa31 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 20:15:37 +0200 Subject: [PATCH 070/379] Update deprecation notice --- webserver/controller/controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 002ba17e..ff7175c0 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -16,7 +16,7 @@ export class Controller { * @param value */ public set type(value = 'text/html') { - Logger.warning('Setting type on controller itself is deprecated, please use "Controller.headers.set()" instead.'); + Logger.warning('Setting type on controller itself is deprecated, please use "Controller.response.withHeader()" instead.'); this.response.withHeader('Content-Type', value); } From 7d1e6480fb52984027e66ae91db950b413dfe63f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 20:22:20 +0200 Subject: [PATCH 071/379] Replace 'any' with a proper type --- webserver/http/response-builder.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts index 89966063..c7a050fc 100644 --- a/webserver/http/response-builder.ts +++ b/webserver/http/response-builder.ts @@ -1,5 +1,9 @@ import { StatusCodes } from "./status-codes.ts"; +interface ResponseHeader { + [key: string]: string; +} + export class ResponseBuilder { private readonly _headers: Map> = new Map>(); private _status = StatusCodes.OK; @@ -104,11 +108,13 @@ export class ResponseBuilder { * Build our final response that can be sent back to the client. */ public build(): Response { - const headers: any = {}; - for(const [name, value] of this.getHeaders()) { - headers[name] = value; + // Build our headers + const headers: ResponseHeader = {}; + for(const name of this.getHeaders().keys()) { + headers[name] = this.getHeaderLine(name); } + // Return our final response return new Response( this._body, { From 540ebf46af182f64ae12e78126229c57280b2b80 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 20:22:31 +0200 Subject: [PATCH 072/379] Update types on properties --- webserver/http/response-builder.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts index c7a050fc..01a1f0d2 100644 --- a/webserver/http/response-builder.ts +++ b/webserver/http/response-builder.ts @@ -6,8 +6,8 @@ interface ResponseHeader { export class ResponseBuilder { private readonly _headers: Map> = new Map>(); - private _status = StatusCodes.OK; - private _body: string = ''; + private _status: StatusCodes = StatusCodes.OK; + private _body = ''; public constructor() { // Set default headers From 9e88ba9cc24c4587d9f90b6b6668375d19ae0fed Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 20:28:54 +0200 Subject: [PATCH 073/379] Get rid of more any types --- webserver/controller/controller.ts | 8 ++++++-- webserver/renderers/handlebars.ts | 9 +++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index ff7175c0..7ff5cb62 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -4,10 +4,14 @@ import { Handlebars } from "../renderers/handlebars.ts"; import { ResponseBuilder } from "../http/response-builder.ts"; import { Request } from "../http/request.ts"; +export interface ViewVariable { + [key: string]: string|number; +} + export class Controller { protected static readonly _templateDir = `file://${Deno.cwd()}/src/templates`; protected response: ResponseBuilder = new ResponseBuilder(); - protected vars: any = {}; + protected vars: ViewVariable = {}; /** * Set the 'Content-Type' header @@ -31,7 +35,7 @@ export class Controller { * @param key * @param value */ - protected set(key: string, value: any) { this.vars[key] = value; } + protected set(key: string, value: string|number) { this.vars[key] = value; } /** * Render the page output diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index e1c3bd6e..da5e80f2 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -1,11 +1,16 @@ import { handlebarsEngine } from "https://raw.githubusercontent.com/FinlayDaG33k/view-engine/patch-1/mod.ts"; import { Logger } from "../../logging/logger.ts"; import { raise } from "../../util/raise.ts"; +import { ViewVariable } from "../controller/controller.ts"; + +interface CacheItem { + [key: string]: string; +} export class Handlebars { - private static _cache = {}; + private static _cache: CacheItem = {}; - public static async render(path: string, vars: any = {}, cache = true): Promise { + public static async render(path: string, vars: ViewVariable = {}, cache = true): Promise { // Load our template const template = await Handlebars.getTemplate(path, cache) ?? raise('Could not load template'); From e55c7b38c5d8f5117f787645374dfdf7fcf784f3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 20:29:03 +0200 Subject: [PATCH 074/379] Cast everything to string --- webserver/controller/controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 7ff5cb62..e26ac2ec 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -49,7 +49,7 @@ export class Controller { this.response.withBody(JSON.stringify(this.vars['data'])); break; case 'text/plain': - this.response.withBody(this.vars['message']); + this.response.withBody(this.vars['message'] as string); break; case 'text/html': default: From bdea0f86bc677bce85004aced2dc39f51684c4bb Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 20:31:19 +0200 Subject: [PATCH 075/379] Fix errors --- webserver/controller/controller.ts | 2 +- webserver/http/request.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index e26ac2ec..8d57c9de 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -53,7 +53,7 @@ export class Controller { break; case 'text/html': default: - const body = await Handlebars.render(`${Controller._templateDir}/${Inflector.lcfirst(this.name)}/${this.action}.hbs`, this.vars) ?? ''; + const body = await Handlebars.render(`${Controller._templateDir}/${Inflector.lcfirst(this.request.args.route.controller)}/${this.request.args.route.action}.hbs`, this.vars) ?? ''; this.response.withBody(body); } } diff --git a/webserver/http/request.ts b/webserver/http/request.ts index 7f4f1ea3..23d4dea6 100644 --- a/webserver/http/request.ts +++ b/webserver/http/request.ts @@ -2,7 +2,7 @@ import { RouteArgs } from "../routing/router.ts"; export class Request { constructor( - private readonly args: RouteArgs + public readonly args: RouteArgs ) { } } From 7d182a3e0349d805af6d83f16f4ed1f34ae2537e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 20:38:34 +0200 Subject: [PATCH 076/379] Fix more any types --- webserver/routing/router.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 53779131..a6b2ae67 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -11,6 +11,10 @@ interface Route { method?: string; } +interface RouteCache { + [key: string]: Module; +} + export interface RouteArgs { route: Route; body: string; @@ -22,7 +26,7 @@ export class Router { private static readonly _controllerDir = `file://${Deno.cwd()}/src/controller`; private static routes: Route[] = []; public static getRoutes() { return Router.routes; } - private static _cache = {}; + private static _cache: RouteCache = {}; /** * Match the controller and action to a route From 2c754d8cf17f37cbf4f80e57add42e1803f2d329 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 22:35:48 +0200 Subject: [PATCH 077/379] Move more of the routing logic to the router to clean up the Webserver class --- webserver/routing/router.ts | 49 ++++++++++++++++++++++++++++--------- webserver/webserver.ts | 28 ++------------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index a6b2ae67..e8c46122 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -3,6 +3,7 @@ import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../util/inflector.ts"; import { Logger } from "../../logging/logger.ts"; import { Request as ChompRequest } from "../http/request.ts"; +import { StatusCodes } from "../http/status-codes.ts"; interface Route { path: string; @@ -60,19 +61,38 @@ export class Router { /** * Execute the requested controller action * - * @param args + * @param request * @returns Promise */ - public async execute(args: RouteArgs): Promise { - // Make sure a route was specified - if(args.route === null) return null; + public async execute(request: Request): Promise { + // Make sure a route was found + // Otherwise return a 404 response + const route = this.route(request); + if(!route || !route.route) { + return new Response( + 'The requested page could not be found.', + { + status: StatusCodes.NOT_FOUND, + headers: { + 'Content-Type': 'text/plain' + } + } + ); + } + + const req = new ChompRequest({ + route: route.route, + body: await this.getBody(request), + params: await this.getParams(route.route, route.path), + auth: this.getAuth(request), + }); // Import and cache controller file if need be - if(!(args.route.controller in Router._cache)) { + if(!(req.args.route.controller in Router._cache)) { try { - Router._cache[args.route.controller] = await import(`${Router._controllerDir}/${Inflector.lcfirst(args.route.controller)}.controller.ts`); + Router._cache[req.args.route.controller] = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.args.route.controller)}.controller.ts`); } catch(e) { - Logger.error(`Could not import "${args.route.controller}": ${e.message}`, e.stack); + Logger.error(`Could not import "${req.args.route.controller}": ${e.message}`, e.stack); return new Response( 'Internal Server Error', { @@ -88,10 +108,10 @@ export class Router { // Run our controller try { // Instantiate the controller - const controller = new Router._cache[args.route.controller][`${args.route.controller}Controller`](new ChompRequest(args)); + const controller = new Router._cache[req.args.route.controller][`${req.args.route.controller}Controller`](req); // Execute our action - await controller[args.route.action](); + await controller[req.args.route.action](); // Render the body await controller.render(); @@ -99,7 +119,7 @@ export class Router { // Return our response return controller.response.build(); } catch(e) { - Logger.error(`Could not execute "${args.route.controller}": ${e.message}`, e.stack); + Logger.error(`Could not execute "${req.args.route.controller}": ${e.message}`, e.stack); return new Response( 'An Internal Server Error Occurred', { @@ -155,8 +175,7 @@ export class Router { public getAuth(request: Request): string { // Get our authorization header // Return it or empty string if none found - const header = request.headers.get("authorization"); - return header ?? ''; + return request.headers.get("authorization") ?? ''; } /** @@ -167,7 +186,13 @@ export class Router { * @returns void */ public static add(route: Route): void { + // Check if a method was set, use default if not if(!('method' in route)) route.method = 'GET'; + + // Pascalize the controller + route.controller = Inflector.pascalize(route.controller); + + // Add the route to our routes Router.routes.push(route); } } diff --git a/webserver/webserver.ts b/webserver/webserver.ts index 1c866944..5060686f 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -30,32 +30,8 @@ export class Webserver { for await(const request of httpConn) { Logger.debug(`Request from "${(conn.remoteAddr as Deno.NetAddr).hostname!}:${(conn.remoteAddr as Deno.NetAddr).port!}": ${request.request.method} | ${request.request.url}`); try { - // Try to find a matching route - // Respond with 404 if not found - const routing = this.router.route(request.request); - if(!routing || !routing.route) { - await request.respondWith(new Response( - 'The requested page could not be found.', - { - status: StatusCodes.NOT_FOUND, - headers: { - 'Content-Type': 'text/plain' - } - } - )); - return; - } - - // Execute the route - const response = await this.router.execute({ - route: routing.route, - body: await this.router.getBody(request.request), - params: await this.router.getParams(routing.route, routing.path ?? '/'), - auth: this.router.getAuth(request.request) - }); - - // Check if the response was empty or not - if(!response) throw Error('Response was empty'); + // Run the required route + const response: Response = await this.router.execute(request.request); // Send our response await request.respondWith(response); From 5340a68f026d6dda4979bbe2bfa10db38033be97 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 22:45:46 +0200 Subject: [PATCH 078/379] Add comment --- webserver/routing/router.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index e8c46122..8f81e2f8 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -80,6 +80,7 @@ export class Router { ); } + // Build our Request object const req = new ChompRequest({ route: route.route, body: await this.getBody(request), From 1dcb057d685891b39bd85ac0f1daeafd06f96593 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 22:46:32 +0200 Subject: [PATCH 079/379] Remove an "any" type --- webserver/routing/router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 8f81e2f8..9c8fd371 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -19,7 +19,7 @@ interface RouteCache { export interface RouteArgs { route: Route; body: string; - params: any; + params: { [key: string]: string; }; auth?: string; } From 12607266eaa0b4668de67d1ab13ec78c500cf21e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 22:49:53 +0200 Subject: [PATCH 080/379] Add withType method --- webserver/controller/controller.ts | 4 ++-- webserver/http/response-builder.ts | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 8d57c9de..764fc281 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -16,11 +16,11 @@ export class Controller { /** * Set the 'Content-Type' header * - * @deprecated Please use "Controller.response.withHeader()" instead. + * @deprecated Please use "Controller.response.withType()" instead. * @param value */ public set type(value = 'text/html') { - Logger.warning('Setting type on controller itself is deprecated, please use "Controller.response.withHeader()" instead.'); + Logger.warning('Setting type on controller itself is deprecated, please use "Controller.response.withType()" instead.'); this.response.withHeader('Content-Type', value); } diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts index 01a1f0d2..3af46bee 100644 --- a/webserver/http/response-builder.ts +++ b/webserver/http/response-builder.ts @@ -84,6 +84,16 @@ export class ResponseBuilder { return this; } + /** + * Set the response MIME + * + * @param mime + */ + public withType(mime = 'text/html'): ResponseBuilder { + this.withHeader('Content-Type', mime); + return this; + } + /** * Set our response status. * From c461dd394aa8f9e610d796960f802b6c5e2ffc6d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 23:12:32 +0200 Subject: [PATCH 081/379] Update type --- webserver/controller/controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 764fc281..5c0b446c 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -5,7 +5,7 @@ import { ResponseBuilder } from "../http/response-builder.ts"; import { Request } from "../http/request.ts"; export interface ViewVariable { - [key: string]: string|number; + [key: string]: string|number|unknown; } export class Controller { @@ -35,7 +35,7 @@ export class Controller { * @param key * @param value */ - protected set(key: string, value: string|number) { this.vars[key] = value; } + protected set(key: string, value: string|number|unknown) { this.vars[key] = value; } /** * Render the page output From 7775c000798090c99cc4917adb014b9bf232b622 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 28 Jul 2023 23:41:28 +0200 Subject: [PATCH 082/379] Cleanup Request a bit --- webserver/http/request.ts | 11 +++++++++-- webserver/routing/router.ts | 30 +++++++++++++++--------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/webserver/http/request.ts b/webserver/http/request.ts index 23d4dea6..813d7369 100644 --- a/webserver/http/request.ts +++ b/webserver/http/request.ts @@ -1,8 +1,15 @@ -import { RouteArgs } from "../routing/router.ts"; +import { Route } from "../routing/router.ts"; + +export interface RequestParameters { + [name: string]: string; +} export class Request { constructor( - public readonly args: RouteArgs + public readonly route: Route, + public readonly body: string, + public readonly params: RequestParameters, + public readonly auth: string, ) { } } diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 9c8fd371..61da2e8b 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -2,10 +2,10 @@ import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts" import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../util/inflector.ts"; import { Logger } from "../../logging/logger.ts"; -import { Request as ChompRequest } from "../http/request.ts"; +import { Request as ChompRequest, RequestParameters } from "../http/request.ts"; import { StatusCodes } from "../http/status-codes.ts"; -interface Route { +export interface Route { path: string; controller: string; action: string; @@ -81,19 +81,19 @@ export class Router { } // Build our Request object - const req = new ChompRequest({ - route: route.route, - body: await this.getBody(request), - params: await this.getParams(route.route, route.path), - auth: this.getAuth(request), - }); + const req = new ChompRequest( + route.route, + await this.getBody(request), + await this.getParams(route.route, route.path), + this.getAuth(request), + ); // Import and cache controller file if need be - if(!(req.args.route.controller in Router._cache)) { + if(!(req.route.controller in Router._cache)) { try { - Router._cache[req.args.route.controller] = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.args.route.controller)}.controller.ts`); + Router._cache[req.route.controller] = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.route.controller)}.controller.ts`); } catch(e) { - Logger.error(`Could not import "${req.args.route.controller}": ${e.message}`, e.stack); + Logger.error(`Could not import "${req.route.controller}": ${e.message}`, e.stack); return new Response( 'Internal Server Error', { @@ -109,10 +109,10 @@ export class Router { // Run our controller try { // Instantiate the controller - const controller = new Router._cache[req.args.route.controller][`${req.args.route.controller}Controller`](req); + const controller = new Router._cache[req.route.controller][`${req.route.controller}Controller`](req); // Execute our action - await controller[req.args.route.action](); + await controller[req.route.action](); // Render the body await controller.render(); @@ -120,7 +120,7 @@ export class Router { // Return our response return controller.response.build(); } catch(e) { - Logger.error(`Could not execute "${req.args.route.controller}": ${e.message}`, e.stack); + Logger.error(`Could not execute "${req.route.controller}": ${e.message}`, e.stack); return new Response( 'An Internal Server Error Occurred', { @@ -140,7 +140,7 @@ export class Router { * @param path * @returns Promise<{ [key: string]: string }> */ - public async getParams(route: Route, path: string): Promise<{ [key: string]: string }> { + public async getParams(route: Route, path: string): Promise { const keys: any[] = []; const r = pathToRegexp(route.path, keys).exec(path) || []; From e8eee396d315f95d091086b3f35f99e83afe82c2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 00:18:00 +0200 Subject: [PATCH 083/379] Try to prevent people from accidentally screwing with the important data --- webserver/controller/controller.ts | 44 +++++++++++++++++++------- webserver/http/request.ts | 23 +++++++++++--- webserver/routing/route.ts | 17 ++++++++++ webserver/routing/router.ts | 51 +++++++++++++++--------------- 4 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 webserver/routing/route.ts diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 5c0b446c..03fa42b1 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -9,19 +9,19 @@ export interface ViewVariable { } export class Controller { - protected static readonly _templateDir = `file://${Deno.cwd()}/src/templates`; - protected response: ResponseBuilder = new ResponseBuilder(); - protected vars: ViewVariable = {}; + private static readonly _templateDir = `file://${Deno.cwd()}/src/templates`; + private _response: ResponseBuilder = new ResponseBuilder(); + private _vars: ViewVariable = {}; /** * Set the 'Content-Type' header * - * @deprecated Please use "Controller.response.withType()" instead. + * @deprecated Please use "Controller.getResponse().withType()" instead. * @param value */ public set type(value = 'text/html') { - Logger.warning('Setting type on controller itself is deprecated, please use "Controller.response.withType()" instead.'); - this.response.withHeader('Content-Type', value); + Logger.warning('Setting type on controller itself is deprecated, please use "Controller.getResponse().withType()" instead.'); + this.getResponse().withHeader('Content-Type', value); } constructor( @@ -29,13 +29,31 @@ export class Controller { ) { } + /** + * Get the request object for this controller + * + * @protected + */ + protected getRequest(): typeof this.request { + return this.request; + } + + /** + * Get the response object for this controller + * + * @protected + */ + protected getResponse(): typeof this._response { + return this._response; + } + /** * Set a view variable * * @param key * @param value */ - protected set(key: string, value: string|number|unknown) { this.vars[key] = value; } + protected set(key: string, value: string|number|unknown) { this._vars[key] = value; } /** * Render the page output @@ -44,17 +62,19 @@ export class Controller { * @returns Promise */ public async render(): Promise { - switch(this.response.getHeaderLine('Content-Type').toLowerCase()) { + switch(this.getResponse().getHeaderLine('Content-Type').toLowerCase()) { case 'application/json': - this.response.withBody(JSON.stringify(this.vars['data'])); + this.getResponse().withBody(JSON.stringify(this._vars['data'])); break; case 'text/plain': - this.response.withBody(this.vars['message'] as string); + this.getResponse().withBody(this._vars['message'] as string); break; case 'text/html': default: - const body = await Handlebars.render(`${Controller._templateDir}/${Inflector.lcfirst(this.request.args.route.controller)}/${this.request.args.route.action}.hbs`, this.vars) ?? ''; - this.response.withBody(body); + const controller = Inflector.lcfirst(this.getRequest().getRoute().getController()); + const action = this.getRequest().getRoute().getAction(); + const body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars) ?? ''; + this.getResponse().withBody(body); } } } diff --git a/webserver/http/request.ts b/webserver/http/request.ts index 813d7369..6a4a2728 100644 --- a/webserver/http/request.ts +++ b/webserver/http/request.ts @@ -1,4 +1,4 @@ -import { Route } from "../routing/router.ts"; +import { Route } from "../routing/route.ts"; export interface RequestParameters { [name: string]: string; @@ -6,10 +6,23 @@ export interface RequestParameters { export class Request { constructor( - public readonly route: Route, - public readonly body: string, - public readonly params: RequestParameters, - public readonly auth: string, + private readonly route: Route, + private readonly body: string, + private readonly params: RequestParameters, + private readonly auth: string, ) { } + + public getRoute(): typeof this.route { return this.route; } + + public getBody(): typeof this.body { return this.body; } + + public getParams(): typeof this.params { return this.params; } + + public getParam(name: string): string|null { + if(name in this.params) return this.params[name]; + return null; + } + + public getAuth(): typeof this.auth { return this.auth; } } diff --git a/webserver/routing/route.ts b/webserver/routing/route.ts new file mode 100644 index 00000000..332ee1cc --- /dev/null +++ b/webserver/routing/route.ts @@ -0,0 +1,17 @@ +export class Route { + public constructor( + private readonly path: string, + private readonly controller: string, + private readonly action: string, + private readonly method: string + ) { + } + + public getPath(): typeof this.path { return this.path; } + + public getController(): typeof this.controller { return this.controller; } + + public getAction(): typeof this.action { return this.action; } + + public getMethod(): typeof this.method { return this.method; } +} diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 61da2e8b..47c2f3f9 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -4,20 +4,21 @@ import { Inflector } from "../../util/inflector.ts"; import { Logger } from "../../logging/logger.ts"; import { Request as ChompRequest, RequestParameters } from "../http/request.ts"; import { StatusCodes } from "../http/status-codes.ts"; +import { Route as ChompRoute } from "./route.ts"; -export interface Route { +interface RouteCache { + [key: string]: Module; +} + +interface Route { path: string; controller: string; action: string; method?: string; } -interface RouteCache { - [key: string]: Module; -} - export interface RouteArgs { - route: Route; + route: ChompRoute; body: string; params: { [key: string]: string; }; auth?: string; @@ -25,7 +26,7 @@ export interface RouteArgs { export class Router { private static readonly _controllerDir = `file://${Deno.cwd()}/src/controller`; - private static routes: Route[] = []; + private static routes: ChompRoute[] = []; public static getRoutes() { return Router.routes; } private static _cache: RouteCache = {}; @@ -47,10 +48,10 @@ export class Router { // Check if it's the right path // Return the route if route found for (const route of Router.routes) { - if(route.method !== request.method) continue; + if(route.getMethod() !== request.method) continue; // Make sure we have a matching route - const matches = pathToRegexp(route.path).exec(path); + const matches = pathToRegexp(route.getPath()).exec(path); if(matches) return { route: route, path: path @@ -89,11 +90,11 @@ export class Router { ); // Import and cache controller file if need be - if(!(req.route.controller in Router._cache)) { + if(!(req.getRoute().getController() in Router._cache)) { try { - Router._cache[req.route.controller] = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.route.controller)}.controller.ts`); + Router._cache[req.getRoute().getController()] = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.getRoute().getController())}.controller.ts`); } catch(e) { - Logger.error(`Could not import "${req.route.controller}": ${e.message}`, e.stack); + Logger.error(`Could not import "${req.getRoute().getController()}": ${e.message}`, e.stack); return new Response( 'Internal Server Error', { @@ -109,18 +110,18 @@ export class Router { // Run our controller try { // Instantiate the controller - const controller = new Router._cache[req.route.controller][`${req.route.controller}Controller`](req); + const controller = new Router._cache[req.getRoute().getController()][`${req.getRoute().getController()}Controller`](req); // Execute our action - await controller[req.route.action](); + await controller[req.getRoute().getAction()](); // Render the body await controller.render(); // Return our response - return controller.response.build(); + return controller.getResponse().build(); } catch(e) { - Logger.error(`Could not execute "${req.route.controller}": ${e.message}`, e.stack); + Logger.error(`Could not execute "${req.getRoute().getController()}": ${e.message}`, e.stack); return new Response( 'An Internal Server Error Occurred', { @@ -140,9 +141,9 @@ export class Router { * @param path * @returns Promise<{ [key: string]: string }> */ - public async getParams(route: Route, path: string): Promise { + public async getParams(route: ChompRoute, path: string): Promise { const keys: any[] = []; - const r = pathToRegexp(route.path, keys).exec(path) || []; + const r = pathToRegexp(route.getPath(), keys).exec(path) || []; return keys.reduce((acc, key, i) => ({ [key.name]: r[i + 1], ...acc }), {}); } @@ -187,13 +188,11 @@ export class Router { * @returns void */ public static add(route: Route): void { - // Check if a method was set, use default if not - if(!('method' in route)) route.method = 'GET'; - - // Pascalize the controller - route.controller = Inflector.pascalize(route.controller); - - // Add the route to our routes - Router.routes.push(route); + Router.routes.push(new ChompRoute( + route.path, + Inflector.pascalize(route.controller), + route.action, + route.method ?? 'GET', + )); } } From acfda8d69ef0790d60f1152578d47b45ca34b28f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 00:27:37 +0200 Subject: [PATCH 084/379] Make sure controller extends our own controller --- webserver/routing/router.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 47c2f3f9..d604ab01 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -5,6 +5,8 @@ import { Logger } from "../../logging/logger.ts"; import { Request as ChompRequest, RequestParameters } from "../http/request.ts"; import { StatusCodes } from "../http/status-codes.ts"; import { Route as ChompRoute } from "./route.ts"; +import { Controller } from "../controller/controller.ts"; +import { raise } from "../../util/raise.ts"; interface RouteCache { [key: string]: Module; @@ -92,7 +94,21 @@ export class Router { // Import and cache controller file if need be if(!(req.getRoute().getController() in Router._cache)) { try { - Router._cache[req.getRoute().getController()] = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.getRoute().getController())}.controller.ts`); + // Import the module + const module = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.getRoute().getController())}.controller.ts`); + + // Make sure the controller class was found + if(!(`${req.getRoute().getController()}Controller` in module)) { + raise(`No class "${req.getRoute().getController()}Controller" could be found.`); + } + + // Make sure the controller class extends our base controller + if(!(module[`${req.getRoute().getController()}Controller`].prototype instanceof Controller)) { + raise(`Class "${req.getRoute().getController()}Controller" does not properly extend our controller.`); + } + + // Add the module to our cache + Router._cache[req.getRoute().getController()] = module; } catch(e) { Logger.error(`Could not import "${req.getRoute().getController()}": ${e.message}`, e.stack); return new Response( From 1315bcc8a6105d8cca0b3e9037febc63d05eb6b5 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 00:28:13 +0200 Subject: [PATCH 085/379] Fix phrasing --- webserver/routing/router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index d604ab01..b9e8c842 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -104,7 +104,7 @@ export class Router { // Make sure the controller class extends our base controller if(!(module[`${req.getRoute().getController()}Controller`].prototype instanceof Controller)) { - raise(`Class "${req.getRoute().getController()}Controller" does not properly extend our controller.`); + raise(`Class "${req.getRoute().getController()}Controller" does not properly extend Chomp's controller.`); } // Add the module to our cache From 12d37d1f1b5bc27d13d4aa354fc97e559647f754 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 00:32:46 +0200 Subject: [PATCH 086/379] Remove unused interface --- webserver/routing/router.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index b9e8c842..54e9ebe7 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -19,13 +19,6 @@ interface Route { method?: string; } -export interface RouteArgs { - route: ChompRoute; - body: string; - params: { [key: string]: string; }; - auth?: string; -} - export class Router { private static readonly _controllerDir = `file://${Deno.cwd()}/src/controller`; private static routes: ChompRoute[] = []; From 7feb778342f2b390a20ab6bf01e9fb017a7c9002 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 11:19:30 +0200 Subject: [PATCH 087/379] Nutty stuff --- communication/mod.ts | 1 + communication/nut.ts | 231 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 communication/nut.ts diff --git a/communication/mod.ts b/communication/mod.ts index bdef1d50..b7033303 100644 --- a/communication/mod.ts +++ b/communication/mod.ts @@ -3,5 +3,6 @@ export * from "./druid.ts"; export * from "./graphql.ts"; export * from "./loki.ts"; export * from "./ntfy.ts"; +export * from "./nut.ts"; export * from "./rcon.ts"; export * from "./redis.ts"; diff --git a/communication/nut.ts b/communication/nut.ts new file mode 100644 index 00000000..65e2183c --- /dev/null +++ b/communication/nut.ts @@ -0,0 +1,231 @@ +import { Logger } from "../logging/logger.ts"; + +export class NutState { + public static readonly WAITING = 0; + public static readonly IDLE = 1; +} + +export class Nut { + private host: string = ''; + private port: number = 3493; + private client: any = null; + private _status: number = NutState.IDLE; + private callback: any = null; + private dataBuf: string = ''; + + public get status(): number { return this._status; } + + constructor(host: string|undefined, port: number = 3493) { + if(typeof host === 'undefined') { + Logger.error(`Could not register monitor for "UPS": No NUT host defined!`); + return this; + } + + this.host = host; + this.port = port; + } + + public async connect() { + // Instantiate a new client + this.client = await Deno.connect({ hostname: this.host, port: this.port }); + + // Create pseudo-event handler + this.onReceive(); + } + + public async send(cmd: string, callback: any) { + if(this._status !== NutState.IDLE) throw new Error(`NUT not ready to send new data yet!`); + this._status = NutState.WAITING; + this.callback = callback; + + // Encode our command string + const data = new TextEncoder().encode(`${cmd}\n`); + + // Send our data over the connection + await this.client.write(data); + } + + public async close() { + //this.send(`LOGOUT`); + this.client.close(); + } + + private async onReceive() { + for await (const buffer of Deno.iter(this.client)) { + this.dataBuf += new TextDecoder().decode(buffer); + this.callback(this.dataBuf); + } + } + + private onError(err: any) { + console.log(err); + } + + public getLoad(name: string|undefined): Promise { + if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + + return new Promise(async (resolve: any, reject: any) => { + await this.send(`GET VAR ${name} ups.load`, (data: any) => { + // Get our power + const matches = /VAR (?:[a-zA-Z0-9]+) ups\.load "([0-9]+)"/.exec(data); + if(matches === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + if(typeof matches![1] === 'undefined' || matches![1] === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(Number(matches![1])); + }); + }); + } + + public getPowerLimit(name: string|undefined): Promise { + if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + + return new Promise(async (resolve: any, reject: any) => { + await this.send(`GET VAR ${name} ups.realpower.nominal`, (data: any) => { + // Get our power + const matches = /VAR (?:[a-zA-Z0-9]+) ups\.realpower\.nominal "([0-9]+)"/.exec(data); + if(matches === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + if(typeof matches![1] === 'undefined' || matches![1] === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(Number(matches![1])); + }); + }); + } + + public getCharge(name: string|undefined): Promise { + if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + + return new Promise(async (resolve: any, reject: any) => { + await this.send(`GET VAR ${name} battery.charge`, (data: any) => { + // Get our power + const matches = /VAR (?:[a-zA-Z0-9]+) battery\.charge "([0-9]+)"/.exec(data); + if(matches === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + if(typeof matches![1] === 'undefined' || matches![1] === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(Number(matches![1])); + }); + }); + } + + public getRuntime(name: string|undefined): Promise { + if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + + return new Promise(async (resolve: any, reject: any) => { + await this.send(`GET VAR ${name} battery.runtime`, (data: any) => { + // Get our power + const matches = /VAR (?:[a-zA-Z0-9]+) battery\.runtime "([0-9]+)"/.exec(data); + if(matches === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + if(typeof matches![1] === 'undefined' || matches![1] === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(Number(matches![1])); + }); + }); + } + + public getStatus(name: string|undefined): Promise { + if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + + return new Promise(async (resolve: any, reject: any) => { + await this.send(`GET VAR ${name} ups.status`, (data: any) => { + // Get our power + const matches = /VAR (?:[a-zA-Z0-9]+) ups\.status "([0-9]+)"/.exec(data); + if(matches === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + if(typeof matches![1] === 'undefined' || matches![1] === null) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(0); + return; + } + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(Number(matches![1])); + }); + }); + } + + public get UPSList() { + return new Promise(async (resolve: any, reject: any) => { + await this.send(`LIST UPS`, (data: any) => { + const dataArray = data.split('\n'); + const vars: any = {}; + for (const line of dataArray) { + // Check if we have an error + if(line.indexOf('ERR') === 0) { + this._status = NutState.IDLE; + this.dataBuf = ''; + reject(line.slice(4)); + return; + } + + // Find UPS entries by regex + // Check if 3 items have been found + // Add them to our object + if(line.indexOf('UPS ') === 0) { + const matches = /^UPS\s+(.+)\s+"(.*)"/.exec(line); + if(matches === null) continue; + if(matches.length < 3) continue; + vars[matches[1]] = matches[2]; + continue; + } + + // Resolve if we hit the end + if(line.indexOf('END LIST UPS') === 0) { + this._status = NutState.IDLE; + this.dataBuf = ''; + resolve(vars); + return; + } + } + }); + }); + } +} From 6c59b47dd3420d76d37b6030a1fe5763ca98b4b8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 17:05:14 +0200 Subject: [PATCH 088/379] Update deprecation messages --- util/lcfirst.ts | 8 +++++++- util/ucfirst.ts | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/util/lcfirst.ts b/util/lcfirst.ts index 3cba0958..6f916ef1 100644 --- a/util/lcfirst.ts +++ b/util/lcfirst.ts @@ -1,6 +1,12 @@ import { Logger } from "../logging/logger.ts"; +/** + * Uppercase the first character of a string + * + * @deprecated Please use Inflector.lcfirst() instead. + * @param input + */ export function lcfirst(input: string): string { - Logger.debug('Usage of "util/lcfirst" is deprecated, please use "util/inflector#lcfirst" instead.'); + Logger.debug('Usage of "util/lcfirst" is deprecated, please use "Inflector.lcfirst()" instead.'); return input.charAt(0).toLowerCase() + input.slice(1); } diff --git a/util/ucfirst.ts b/util/ucfirst.ts index 4dcd50ca..1c00cfac 100644 --- a/util/ucfirst.ts +++ b/util/ucfirst.ts @@ -1,6 +1,12 @@ import { Logger } from "../logging/logger.ts"; +/** + * Uppercase the first character of a string + * + * @deprecated Please use Inflector.ucfirst() instead. + * @param input + */ export function ucfirst(input: string): string { - Logger.debug('Usage of "util/ucfirst" is deprecated, please use "util/inflector#ucfirst" instead.'); + Logger.debug('Usage of "util/ucfirst" is deprecated, please use "Inflector.ucfirst()" instead.'); return input.charAt(0).toUpperCase() + input.slice(1); } From 280d246eedef7bfdaa8ea60b9b70e6bf89a72fd6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 17:10:04 +0200 Subject: [PATCH 089/379] Remove env completely --- common/env.ts | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 common/env.ts diff --git a/common/env.ts b/common/env.ts deleted file mode 100644 index 912e1e9d..00000000 --- a/common/env.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Logger } from "../logging/logger.ts"; -export { config as env } from "https://deno.land/x/dotenv@v3.2.0/mod.ts"; -Logger.warning("Usage of \"deno-lib/common/env.ts\" is deprecated and may be removed soon, please use \"deno-lib/common/configure.ts\" instead."); From aa57e5fd31e4cce0223a4818a9f75521d24d9fa6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 18:38:54 +0200 Subject: [PATCH 090/379] Make the Webserver module only export what's really needed --- webserver/http/mod.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/webserver/http/mod.ts b/webserver/http/mod.ts index 19c54a6d..4a93eacf 100644 --- a/webserver/http/mod.ts +++ b/webserver/http/mod.ts @@ -1,3 +1,2 @@ export * from "./request.ts"; -export * from "./response-builder.ts"; export * from "./status-codes.ts"; From f69e89fa5bfcf4e5392848a4a31c4f85c551aad3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 18:40:51 +0200 Subject: [PATCH 091/379] Remove ucfirst and lcfirst completely --- util/lcfirst.ts | 12 ------------ util/ucfirst.ts | 12 ------------ 2 files changed, 24 deletions(-) delete mode 100644 util/lcfirst.ts delete mode 100644 util/ucfirst.ts diff --git a/util/lcfirst.ts b/util/lcfirst.ts deleted file mode 100644 index 6f916ef1..00000000 --- a/util/lcfirst.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Logger } from "../logging/logger.ts"; - -/** - * Uppercase the first character of a string - * - * @deprecated Please use Inflector.lcfirst() instead. - * @param input - */ -export function lcfirst(input: string): string { - Logger.debug('Usage of "util/lcfirst" is deprecated, please use "Inflector.lcfirst()" instead.'); - return input.charAt(0).toLowerCase() + input.slice(1); -} diff --git a/util/ucfirst.ts b/util/ucfirst.ts deleted file mode 100644 index 1c00cfac..00000000 --- a/util/ucfirst.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Logger } from "../logging/logger.ts"; - -/** - * Uppercase the first character of a string - * - * @deprecated Please use Inflector.ucfirst() instead. - * @param input - */ -export function ucfirst(input: string): string { - Logger.debug('Usage of "util/ucfirst" is deprecated, please use "Inflector.ucfirst()" instead.'); - return input.charAt(0).toUpperCase() + input.slice(1); -} From ef4a305f70737f51d6fe77f269d8117507a02d34 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 18:42:15 +0200 Subject: [PATCH 092/379] Prevent people abusing module files to overfetch what they don't need --- common/mod.ts | 3 --- communication/mod.ts | 8 -------- mod.ts | 9 --------- security/mod.ts | 3 --- util/mod.ts | 9 --------- 5 files changed, 32 deletions(-) delete mode 100644 common/mod.ts delete mode 100644 communication/mod.ts delete mode 100644 mod.ts delete mode 100644 security/mod.ts delete mode 100644 util/mod.ts diff --git a/common/mod.ts b/common/mod.ts deleted file mode 100644 index a41e1d0c..00000000 --- a/common/mod.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./configure.ts"; -export * from "./cron.ts"; -export * from "./time.ts"; diff --git a/communication/mod.ts b/communication/mod.ts deleted file mode 100644 index b7033303..00000000 --- a/communication/mod.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * from "./couchdb.ts"; -export * from "./druid.ts"; -export * from "./graphql.ts"; -export * from "./loki.ts"; -export * from "./ntfy.ts"; -export * from "./nut.ts"; -export * from "./rcon.ts"; -export * from "./redis.ts"; diff --git a/mod.ts b/mod.ts deleted file mode 100644 index 288a77fd..00000000 --- a/mod.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from "./common/mod.ts"; -export * from "./communication/mod.ts"; -export * from "./discord/mod.ts"; -export * from "./logging/mod.ts"; -export * from "./queue/mod.ts"; -export * from "./security/mod.ts"; -export * from "./util/mod.ts"; -export * from "./webserver/mod.ts"; -export * from "./websocket/mod.ts"; diff --git a/security/mod.ts b/security/mod.ts deleted file mode 100644 index 6dbf928e..00000000 --- a/security/mod.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./hash.ts"; -export * from "./password.ts"; -export * from "./random.ts"; diff --git a/util/mod.ts b/util/mod.ts deleted file mode 100644 index 2a1e0afb..00000000 --- a/util/mod.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from "./check-source.ts"; -export * from "./folder-exists.ts"; -export * from "./inflector.ts"; -export * from "./is-ts.ts"; -export * from "./lcfirst.ts"; -export * from "./raise.ts"; -export * from "./time-string.ts"; -export * from "./tokenizer.ts"; -export * from "./ucfirst.ts"; From 5d4892a7c3ef9e34d9ba24dd1258b76ee1ffdad9 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 20:16:44 +0200 Subject: [PATCH 093/379] Do not use CWD (causes bugs on Windows) --- webserver/controller/controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 03fa42b1..27276e26 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -9,7 +9,7 @@ export interface ViewVariable { } export class Controller { - private static readonly _templateDir = `file://${Deno.cwd()}/src/templates`; + private static readonly _templateDir = `./src/templates`; private _response: ResponseBuilder = new ResponseBuilder(); private _vars: ViewVariable = {}; From e580f1dc8d0dfa15efa19f2259a2eb34ad3bd992 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 29 Jul 2023 20:16:58 +0200 Subject: [PATCH 094/379] Add rudimentary cache control --- webserver/http/response-builder.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts index 3af46bee..7cb1cc3c 100644 --- a/webserver/http/response-builder.ts +++ b/webserver/http/response-builder.ts @@ -1,4 +1,5 @@ import { StatusCodes } from "./status-codes.ts"; +import { T as TimeString } from "../../util/time-string.ts"; interface ResponseHeader { [key: string]: string; @@ -114,6 +115,34 @@ export class ResponseBuilder { return this; } + /** + * Add headers to enable client caching + * + * @param duration + */ + public withCache(duration = '+1 day'): ResponseBuilder { + const now = new Date(); + this + .withHeader('Date', now.toUTCString()) + .withHeader('Last-Modified', now.toUTCString()) + .withHeader('Expires', new Date(now.getTime() + TimeString`${duration}`).toUTCString()) + .withHeader( 'max-age', (Math.round(TimeString`${duration}` / 1000)).toString()) + + return this; + } + + /** + * Add headers to instruct the client not to cache the response. + */ + public withDisabledCache(): ResponseBuilder { + this + .withHeader('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT') + .withHeader('Last-Modified', new Date().toUTCString()) + .withHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); + + return this; + } + /** * Build our final response that can be sent back to the client. */ From d6390c91568cba14d76e1d2da0aa860757655609 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 30 Jul 2023 15:25:16 +0200 Subject: [PATCH 095/379] Optimise cache and cut out middleman repo --- webserver/renderers/handlebars.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index da5e80f2..1a54f693 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -1,27 +1,32 @@ -import { handlebarsEngine } from "https://raw.githubusercontent.com/FinlayDaG33k/view-engine/patch-1/mod.ts"; +import { default as hbs } from "https://jspm.dev/handlebars@4.7.6"; import { Logger } from "../../logging/logger.ts"; import { raise } from "../../util/raise.ts"; import { ViewVariable } from "../controller/controller.ts"; interface CacheItem { - [key: string]: string; + [key: string]: Function; } export class Handlebars { private static _cache: CacheItem = {}; public static async render(path: string, vars: ViewVariable = {}, cache = true): Promise { + // Read and execute from cache if possible + if(cache && path in Handlebars._cache) return Handlebars._cache[path](vars); + // Load our template - const template = await Handlebars.getTemplate(path, cache) ?? raise('Could not load template'); + const template = await Handlebars.getTemplate(path) ?? raise('Could not load template'); + + // Compile our template + // Cache it if need be + const compiled = hbs.compile(template) ?? raise('Could not compile template'); + if(cache) if(cache) Handlebars._cache[path] = compiled; // Let the engine render - return handlebarsEngine(template, vars); + return compiled(vars); } - private static async getTemplate(path: string, cache: boolean): Promise { - // Read template from cache if possible - if(cache && path in Handlebars._cache) return Handlebars._cache[path]; - + private static async getTemplate(path: string): Promise { // Make sure out template exists try { await Deno.stat(path); @@ -33,9 +38,6 @@ export class Handlebars { // Read our template const template = await Deno.readTextFile(path); - // Write to cache if need be - if(cache) Handlebars._cache[path] = template; - // Return the template return template; } From cda27f57577c4729078ca10899def51e030ad9f7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 30 Jul 2023 16:56:55 +0200 Subject: [PATCH 096/379] Add Cache class --- common/cache.ts | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 common/cache.ts diff --git a/common/cache.ts b/common/cache.ts new file mode 100644 index 00000000..26c63e11 --- /dev/null +++ b/common/cache.ts @@ -0,0 +1,77 @@ +import { T as TimeString } from "../util/time-string.ts"; + +interface CacheItem { + [key: string]: { + data: unknown; + expires: Date; + } +} + +export class Cache { + private static _items: CacheItem = {}; + + /** + * Add an item to the cache. + * + * @param key + * @param value + * @param expiry + */ + public static set(key: string, value: unknown, expiry = '+1 minute'): void { + Cache._items[key] = { + data: value, + expires: new Date(new Date().getTime() + TimeString`${expiry}`), + }; + } + + /** + * Get an item from the cache + * + * @param key + */ + public static get(key: string): unknown|null { + // Return null if the item doesn't exist + if(!Cache.exists(key)) return null; + + // Return null if the item expired + if(Cache.expired(key)) return null; + + // Return the item's data + return Cache._items[key].data; + } + + /** + * Check whether an item exists in the cache + * + * @param key + */ + public static exists(key: string): boolean { + return key in Cache._items; + } + + /** + * Check whether an item has expired + * + * @param key + */ + public static expired(key: string): boolean { + // If the item doesn't exist, return true + if(!Cache.exists(key)) return true; + + // Check if the expiry date is before our current date + return Cache._items[key].expires < new Date(); + } + + /** + * Remove an item from the cache + * + * @param key + */ + public static remove(key: string): void { + // Return if the item doesn't exist + if(!Cache.exists(key)) return; + + // Delete our item + delete Cache._items[key]; + } +} From 00b71d466fe502d8bb731163abdceb9ce7afe0c4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 31 Jul 2023 01:59:57 +0200 Subject: [PATCH 097/379] Make Router-stuff just completely static --- webserver/routing/router.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 54e9ebe7..a8fc44e7 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -30,7 +30,7 @@ export class Router { * * @param request */ - public route(request: Request) { + public static route(request: Request) { // Get the request path minus the domain const host = request.headers.get("host"); let path = request.url @@ -60,10 +60,10 @@ export class Router { * @param request * @returns Promise */ - public async execute(request: Request): Promise { + public static async execute(request: Request): Promise { // Make sure a route was found // Otherwise return a 404 response - const route = this.route(request); + const route = Router.route(request); if(!route || !route.route) { return new Response( 'The requested page could not be found.', @@ -79,9 +79,9 @@ export class Router { // Build our Request object const req = new ChompRequest( route.route, - await this.getBody(request), - await this.getParams(route.route, route.path), - this.getAuth(request), + await Router.getBody(request), + await Router.getParams(route.route, route.path), + Router.getAuth(request), ); // Import and cache controller file if need be @@ -150,7 +150,7 @@ export class Router { * @param path * @returns Promise<{ [key: string]: string }> */ - public async getParams(route: ChompRoute, path: string): Promise { + public static async getParams(route: ChompRoute, path: string): Promise { const keys: any[] = []; const r = pathToRegexp(route.getPath(), keys).exec(path) || []; @@ -163,7 +163,7 @@ export class Router { * @param request * @returns Promise */ - public async getBody(request: Request): Promise { + public static async getBody(request: Request): Promise { // Make sure a body is set if(request.body === null) return ''; @@ -183,7 +183,7 @@ export class Router { * @param request * @returns string */ - public getAuth(request: Request): string { + public static getAuth(request: Request): string { // Get our authorization header // Return it or empty string if none found return request.headers.get("authorization") ?? ''; From 8d45f992ccba4f4f1e4e636a030223ab23c77162 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 31 Jul 2023 02:02:31 +0200 Subject: [PATCH 098/379] Do not use new for router --- webserver/webserver.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webserver/webserver.ts b/webserver/webserver.ts index 5060686f..7132964b 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -4,7 +4,6 @@ import { StatusCodes } from "./http/status-codes.ts"; export class Webserver { private server: any = null; - private router: Router = new Router(); constructor( private readonly port: number = 80 @@ -31,7 +30,7 @@ export class Webserver { Logger.debug(`Request from "${(conn.remoteAddr as Deno.NetAddr).hostname!}:${(conn.remoteAddr as Deno.NetAddr).port!}": ${request.request.method} | ${request.request.url}`); try { // Run the required route - const response: Response = await this.router.execute(request.request); + const response: Response = await Router.execute(request.request); // Send our response await request.respondWith(response); From c930a9da110cd3f69f858e4caabaaa0212db7e89 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 31 Jul 2023 13:57:30 +0200 Subject: [PATCH 099/379] Allow re-useable components to be loaded --- webserver/controller/component.ts | 8 ++++++++ webserver/controller/controller.ts | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 webserver/controller/component.ts diff --git a/webserver/controller/component.ts b/webserver/controller/component.ts new file mode 100644 index 00000000..724f845b --- /dev/null +++ b/webserver/controller/component.ts @@ -0,0 +1,8 @@ +import { Controller } from "./controller.ts"; + +export class Component { + public constructor( + protected readonly controller: Controller + ) { + } +} diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 27276e26..a5f1ef40 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -3,6 +3,8 @@ import { Inflector } from "../../util/inflector.ts"; import { Handlebars } from "../renderers/handlebars.ts"; import { ResponseBuilder } from "../http/response-builder.ts"; import { Request } from "../http/request.ts"; +import { raise } from "../../util/raise.ts"; +import { Component } from "./component.ts"; export interface ViewVariable { [key: string]: string|number|unknown; @@ -10,6 +12,7 @@ export interface ViewVariable { export class Controller { private static readonly _templateDir = `./src/templates`; + private static readonly _componentDir = `file:///${Deno.cwd()}/src/controller/component`; private _response: ResponseBuilder = new ResponseBuilder(); private _vars: ViewVariable = {}; @@ -47,6 +50,25 @@ export class Controller { return this._response; } + protected async loadComponent(name: string): Promise { + // Import the module + const module = await import(`${Controller._componentDir}/${Inflector.lcfirst(name)}.ts`); + + // Make sure the component class was found + if(!(`${Inflector.ucfirst(name)}Component` in module)) { + raise(`No class "${Inflector.ucfirst(name)}Component" could be found.`); + } + + // Make sure the component class extends our base controller + if(!(module[`${Inflector.ucfirst(name)}Component`].prototype instanceof Component)) { + raise(`Class "${Inflector.ucfirst(name)}Component" does not properly extend Chomp's component.`); + } + + this[Inflector.lcfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); + + return this; + } + /** * Set a view variable * From 33e2b5d2ef52ef160f56db18c4719a41d61e7c5d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 31 Jul 2023 14:44:30 +0200 Subject: [PATCH 100/379] Add components and some more utility functions --- webserver/controller/component.ts | 6 +++++- webserver/controller/controller.ts | 11 ++++++++++- webserver/http/request.ts | 9 +++++++++ webserver/routing/router.ts | 9 ++++++++- webserver/webserver.ts | 2 +- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/webserver/controller/component.ts b/webserver/controller/component.ts index 724f845b..47221e8c 100644 --- a/webserver/controller/component.ts +++ b/webserver/controller/component.ts @@ -2,7 +2,11 @@ import { Controller } from "./controller.ts"; export class Component { public constructor( - protected readonly controller: Controller + private readonly controller: Controller ) { } + + protected getController(): typeof this.controller { + return this.controller; + } } diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index a5f1ef40..8d16a85d 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -32,6 +32,14 @@ export class Controller { ) { } + /** + * Initialize the controller. + * Literally does nothing at this moment except exist to prevent errors. + * + * @protected + */ + public async initialize(): Promise {} + /** * Get the request object for this controller * @@ -64,7 +72,8 @@ export class Controller { raise(`Class "${Inflector.ucfirst(name)}Component" does not properly extend Chomp's component.`); } - this[Inflector.lcfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); + // Add the module as class property + this[Inflector.ucfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); return this; } diff --git a/webserver/http/request.ts b/webserver/http/request.ts index 6a4a2728..7d7423e3 100644 --- a/webserver/http/request.ts +++ b/webserver/http/request.ts @@ -6,13 +6,20 @@ export interface RequestParameters { export class Request { constructor( + private readonly url: string, + private readonly method: string, private readonly route: Route, private readonly body: string, private readonly params: RequestParameters, private readonly auth: string, + private readonly ip: string|null = null, ) { } + public getUrl(): typeof this.url { return this.url; } + + public getMethod(): typeof this.method { return this.method; } + public getRoute(): typeof this.route { return this.route; } public getBody(): typeof this.body { return this.body; } @@ -25,4 +32,6 @@ export class Request { } public getAuth(): typeof this.auth { return this.auth; } + + public getIp(): typeof this.ip { return this.ip; } } diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index a8fc44e7..f026e8a2 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -58,9 +58,10 @@ export class Router { * Execute the requested controller action * * @param request + * @param clientIp * @returns Promise */ - public static async execute(request: Request): Promise { + public static async execute(request: Request, clientIp: string): Promise { // Make sure a route was found // Otherwise return a 404 response const route = Router.route(request); @@ -78,10 +79,13 @@ export class Router { // Build our Request object const req = new ChompRequest( + request.url, + request.method, route.route, await Router.getBody(request), await Router.getParams(route.route, route.path), Router.getAuth(request), + clientIp ); // Import and cache controller file if need be @@ -121,6 +125,9 @@ export class Router { // Instantiate the controller const controller = new Router._cache[req.getRoute().getController()][`${req.getRoute().getController()}Controller`](req); + // Run the controller's initializer + await controller.initialize(); + // Execute our action await controller[req.getRoute().getAction()](); diff --git a/webserver/webserver.ts b/webserver/webserver.ts index 7132964b..959750bd 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -30,7 +30,7 @@ export class Webserver { Logger.debug(`Request from "${(conn.remoteAddr as Deno.NetAddr).hostname!}:${(conn.remoteAddr as Deno.NetAddr).port!}": ${request.request.method} | ${request.request.url}`); try { // Run the required route - const response: Response = await Router.execute(request.request); + const response: Response = await Router.execute(request.request, (conn.remoteAddr as Deno.NetAddr).hostname!); // Send our response await request.respondWith(response); From 82eae584952dc09651d45f2f7fdc5a2bec448fb0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 31 Jul 2023 15:49:13 +0200 Subject: [PATCH 101/379] Build more general-purpose cache for modules --- webserver/controller/controller.ts | 12 ++++++++++ webserver/registry/registry.ts | 35 ++++++++++++++++++++++++++++++ webserver/routing/router.ts | 10 +++++---- 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 webserver/registry/registry.ts diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 8d16a85d..f7503992 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -5,6 +5,7 @@ import { ResponseBuilder } from "../http/response-builder.ts"; import { Request } from "../http/request.ts"; import { raise } from "../../util/raise.ts"; import { Component } from "./component.ts"; +import {Registry} from "../registry/registry.ts"; export interface ViewVariable { [key: string]: string|number|unknown; @@ -59,6 +60,14 @@ export class Controller { } protected async loadComponent(name: string): Promise { + // Check if we already loaded the component before + // Use that if so + if(Registry.has(`${Inflector.ucfirst(name)}Component`)) { + const module = Registry.get(`${Inflector.ucfirst(name)}Component`); + this[Inflector.ucfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); + return this; + } + // Import the module const module = await import(`${Controller._componentDir}/${Inflector.lcfirst(name)}.ts`); @@ -72,6 +81,9 @@ export class Controller { raise(`Class "${Inflector.ucfirst(name)}Component" does not properly extend Chomp's component.`); } + // Add the component to the registry + Registry.add(`${Inflector.ucfirst(name)}Component`, module); + // Add the module as class property this[Inflector.ucfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); diff --git a/webserver/registry/registry.ts b/webserver/registry/registry.ts new file mode 100644 index 00000000..cf4a64c0 --- /dev/null +++ b/webserver/registry/registry.ts @@ -0,0 +1,35 @@ +interface RegistryItem { + [key: string]: Module; +} + +export class Registry { + private static _items: RegistryItem = {}; + + /** + * Add an item to the registry + * + * @param name + * @param module + */ + public static add(name: string, module: Module): void { + Registry._items[name] = module; + } + + /** + * Get an item from the registry + * + * @param name + */ + public static get(name: string): Module|null { + return Registry._items[name] ?? null; + } + + /** + * Check whether the registry has an item with name + * + * @param name + */ + public static has(name: string): boolean { + return name in Registry._items; + } +} diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index f026e8a2..d4afa0bd 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -6,6 +6,7 @@ import { Request as ChompRequest, RequestParameters } from "../http/request.ts"; import { StatusCodes } from "../http/status-codes.ts"; import { Route as ChompRoute } from "./route.ts"; import { Controller } from "../controller/controller.ts"; +import { Registry } from "../registry/registry.ts"; import { raise } from "../../util/raise.ts"; interface RouteCache { @@ -89,7 +90,7 @@ export class Router { ); // Import and cache controller file if need be - if(!(req.getRoute().getController() in Router._cache)) { + if(!Registry.has(req.getRoute().getController())) { try { // Import the module const module = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.getRoute().getController())}.controller.ts`); @@ -104,8 +105,8 @@ export class Router { raise(`Class "${req.getRoute().getController()}Controller" does not properly extend Chomp's controller.`); } - // Add the module to our cache - Router._cache[req.getRoute().getController()] = module; + // Add the module to our registry + Registry.add(`${req.getRoute().getController()}Controller`, module); } catch(e) { Logger.error(`Could not import "${req.getRoute().getController()}": ${e.message}`, e.stack); return new Response( @@ -123,7 +124,8 @@ export class Router { // Run our controller try { // Instantiate the controller - const controller = new Router._cache[req.getRoute().getController()][`${req.getRoute().getController()}Controller`](req); + const module = Registry.get(`${req.getRoute().getController()}Controller`) ?? raise(`"${req.getRoute().getController()}Controller" was not found in registry.`) + const controller = new module[`${req.getRoute().getController()}Controller`](req); // Run the controller's initializer await controller.initialize(); From bd86d482a239e7ab51342f6f5d1767f92b3dce4b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 31 Jul 2023 15:49:45 +0200 Subject: [PATCH 102/379] Remove obsolete code --- webserver/routing/router.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index d4afa0bd..1988a8ba 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -9,10 +9,6 @@ import { Controller } from "../controller/controller.ts"; import { Registry } from "../registry/registry.ts"; import { raise } from "../../util/raise.ts"; -interface RouteCache { - [key: string]: Module; -} - interface Route { path: string; controller: string; @@ -24,7 +20,6 @@ export class Router { private static readonly _controllerDir = `file://${Deno.cwd()}/src/controller`; private static routes: ChompRoute[] = []; public static getRoutes() { return Router.routes; } - private static _cache: RouteCache = {}; /** * Match the controller and action to a route From dc8306ee2962773a72b8c903e6e96521248218ee Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 31 Jul 2023 19:28:34 +0200 Subject: [PATCH 103/379] Allow Brotli-compression --- webserver/controller/controller.ts | 25 +++++++++++++++++++------ webserver/http/request.ts | 3 +++ webserver/routing/router.ts | 1 + 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index f7503992..de34721c 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -5,7 +5,8 @@ import { ResponseBuilder } from "../http/response-builder.ts"; import { Request } from "../http/request.ts"; import { raise } from "../../util/raise.ts"; import { Component } from "./component.ts"; -import {Registry} from "../registry/registry.ts"; +import { Registry } from "../registry/registry.ts"; +import { compress as compressBrotli } from "https://deno.land/x/brotli@v0.1.4/mod.ts"; export interface ViewVariable { [key: string]: string|number|unknown; @@ -105,19 +106,31 @@ export class Controller { * @returns Promise */ public async render(): Promise { + let body = ''; + let canCompress = true; switch(this.getResponse().getHeaderLine('Content-Type').toLowerCase()) { case 'application/json': - this.getResponse().withBody(JSON.stringify(this._vars['data'])); + body = JSON.stringify(this._vars['data']); break; case 'text/plain': - this.getResponse().withBody(this._vars['message'] as string); + body = this._vars['message'] as string; break; case 'text/html': - default: const controller = Inflector.lcfirst(this.getRequest().getRoute().getController()); const action = this.getRequest().getRoute().getAction(); - const body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars) ?? ''; - this.getResponse().withBody(body); + body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars); } + + // Check if we can compress with Brotli + // TODO: Hope that Deno will make this obsolete. + if(this.getRequest().getHeaders().get('accept-encoding').includes('br') && canCompress && body.length > 1024) { + Logger.debug(`Compressing body with brotli: ${body.length}-bytes`); + body = compressBrotli(new TextEncoder().encode(body)); + Logger.debug(`Compressed body with brotli: ${body.length}-bytes`); + this.getResponse().withHeader('Content-Encoding', 'br'); + } + + // Set our final body + this.getResponse().withBody(body); } } diff --git a/webserver/http/request.ts b/webserver/http/request.ts index 7d7423e3..51e13107 100644 --- a/webserver/http/request.ts +++ b/webserver/http/request.ts @@ -9,6 +9,7 @@ export class Request { private readonly url: string, private readonly method: string, private readonly route: Route, + private readonly headers: Headers, private readonly body: string, private readonly params: RequestParameters, private readonly auth: string, @@ -22,6 +23,8 @@ export class Request { public getRoute(): typeof this.route { return this.route; } + public getHeaders(): typeof this.headers { return this.headers ;} + public getBody(): typeof this.body { return this.body; } public getParams(): typeof this.params { return this.params; } diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 1988a8ba..0c7fa044 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -78,6 +78,7 @@ export class Router { request.url, request.method, route.route, + request.headers, await Router.getBody(request), await Router.getParams(route.route, route.path), Router.getAuth(request), From 2a3d3add6ca2b044d1dcce730168251d4fca1746 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 3 Aug 2023 12:42:30 +0200 Subject: [PATCH 104/379] Reorganize a bunch of stuff --- {common => core}/cache.ts | 36 +++++++++++++++++------------- {common => core}/configure.ts | 0 discord/dispatchers/event.ts | 10 ++++----- discord/dispatchers/interaction.ts | 22 +++++++++--------- filesystem/file.ts | 30 +++++++++++++++++++++++++ filesystem/folder.ts | 16 +++++++++++++ logging/logger.ts | 4 ++-- tests/common/configure.test.ts | 2 +- tests/util/inflector.test.ts | 2 +- util/folder-exists.ts | 9 -------- util/is-ts.ts | 5 ----- util/tokenizer.ts | 10 --------- {util => utility}/check-source.ts | 16 +++---------- {common => utility}/cron.ts | 0 {util => utility}/inflector.ts | 10 ++++----- {util => utility}/raise.ts | 2 +- utility/text.ts | 25 +++++++++++++++++++++ {util => utility}/time-string.ts | 0 {common => utility}/time.ts | 2 +- webserver/controller/controller.ts | 8 +++---- webserver/http/response-builder.ts | 2 +- webserver/renderers/handlebars.ts | 2 +- webserver/routing/router.ts | 4 ++-- websocket/authenticator.ts | 2 +- websocket/websocket.ts | 2 +- 25 files changed, 131 insertions(+), 90 deletions(-) rename {common => core}/cache.ts (71%) rename {common => core}/configure.ts (100%) create mode 100644 filesystem/file.ts create mode 100644 filesystem/folder.ts delete mode 100644 util/folder-exists.ts delete mode 100644 util/is-ts.ts delete mode 100644 util/tokenizer.ts rename {util => utility}/check-source.ts (88%) rename {common => utility}/cron.ts (100%) rename {util => utility}/inflector.ts (97%) rename {util => utility}/raise.ts (97%) create mode 100644 utility/text.ts rename {util => utility}/time-string.ts (100%) rename {common => utility}/time.ts (96%) diff --git a/common/cache.ts b/core/cache.ts similarity index 71% rename from common/cache.ts rename to core/cache.ts index 26c63e11..151b6b15 100644 --- a/common/cache.ts +++ b/core/cache.ts @@ -1,9 +1,9 @@ -import { T as TimeString } from "../util/time-string.ts"; +import { T as TimeString } from "../utility/time-string.ts"; interface CacheItem { [key: string]: { data: unknown; - expires: Date; + expires: Date|null; } } @@ -12,65 +12,69 @@ export class Cache { /** * Add an item to the cache. - * + * * @param key * @param value - * @param expiry + * @param expiry Can be set to null for never expiring items */ - public static set(key: string, value: unknown, expiry = '+1 minute'): void { + public static set(key: string, value: unknown, expiry: string|null = '+1 minute'): void { + let expiresAt = null; + if(expiry) expiresAt = new Date(new Date().getTime() + TimeString`${expiry}`) + Cache._items[key] = { data: value, - expires: new Date(new Date().getTime() + TimeString`${expiry}`), + expires: expiresAt, }; } /** * Get an item from the cache - * + * * @param key */ public static get(key: string): unknown|null { // Return null if the item doesn't exist if(!Cache.exists(key)) return null; - + // Return null if the item expired if(Cache.expired(key)) return null; - + // Return the item's data return Cache._items[key].data; } /** * Check whether an item exists in the cache - * + * * @param key */ public static exists(key: string): boolean { return key in Cache._items; } - + /** * Check whether an item has expired - * + * * @param key */ public static expired(key: string): boolean { // If the item doesn't exist, return true if(!Cache.exists(key)) return true; - + // Check if the expiry date is before our current date - return Cache._items[key].expires < new Date(); + if(!Cache._items[key].expires) return false; + return Cache._items[key].expires! < new Date(); } /** * Remove an item from the cache - * + * * @param key */ public static remove(key: string): void { // Return if the item doesn't exist if(!Cache.exists(key)) return; - + // Delete our item delete Cache._items[key]; } diff --git a/common/configure.ts b/core/configure.ts similarity index 100% rename from common/configure.ts rename to core/configure.ts diff --git a/discord/dispatchers/event.ts b/discord/dispatchers/event.ts index 4fd19ae3..cb826a12 100644 --- a/discord/dispatchers/event.ts +++ b/discord/dispatchers/event.ts @@ -1,7 +1,7 @@ import { Logger } from "../../logging/logger.ts"; -import { folderExists } from "../../util/folder-exists.ts"; -import { isTs } from "../../util/is-ts.ts"; -import { Inflector } from "../../util/inflector.ts"; +import { Folder } from "../../filesystem/folder.ts"; +import { File } from "../../filesystem/file.ts"; +import { Inflector } from "../../utility/inflector.ts"; interface EventConfig { name: string; @@ -91,7 +91,7 @@ export class EventDispatcher { Logger.debug(`Loading events from "${dir}"...`); // Make sure the interactions directory exists - if(!folderExists(dir)) { + if(!await new Folder(dir).exists()) { Logger.warning(`"${dir}" does not exist, no events to load.`); return; } @@ -102,7 +102,7 @@ export class EventDispatcher { // Load all interactions const promiseQueue: Promise[] = []; for await(const file of files) { - if(!isTs(file.name)) { + if(new File(`${dir}/${file.name}`).ext() === 'ts') { Logger.debug(`File "${file.name}" is not a TS file, skipping...`); continue; } diff --git a/discord/dispatchers/interaction.ts b/discord/dispatchers/interaction.ts index 75e8abcc..eba8b3be 100644 --- a/discord/dispatchers/interaction.ts +++ b/discord/dispatchers/interaction.ts @@ -1,9 +1,9 @@ import {ApplicationCommandOption, ApplicationCommandTypes} from "https://deno.land/x/discordeno@13.0.0/mod.ts"; import { Discord } from "../discord.ts"; import { Logger } from "../../logging/logger.ts"; -import { isTs } from "../../util/is-ts.ts"; -import { folderExists } from "../../util/folder-exists.ts"; -import { Inflector } from "../../util/inflector.ts"; +import { File } from "../../filesystem/file.ts"; +import { Folder } from "../../filesystem/folder.ts"; +import { Inflector } from "../../utility/inflector.ts"; export interface InteractionConfig { name: string; @@ -14,6 +14,7 @@ export interface InteractionConfig { } export class InteractionDispatcher { + private static _interactionsDir = `${Deno.cwd()}/src/interactions`; private static list: InteractionConfig[] = []; private static handlers: any = {}; @@ -57,7 +58,7 @@ export class InteractionDispatcher { public static async add(interaction: InteractionConfig): Promise { try { // Import the interaction handler - InteractionDispatcher.handlers[interaction.handler] = await import(`file://${Deno.cwd()}/src/interactions/${interaction.handler}.ts`) + InteractionDispatcher.handlers[interaction.handler] = await import(`file://${InteractionDispatcher._interactionsDir}/${interaction.handler}.ts`) } catch(e) { Logger.error(`Could not register interaction handler for "${interaction}": ${e.message}`); return; @@ -98,29 +99,28 @@ export class InteractionDispatcher { */ public static async load(): Promise { // Create our directory string - const dir = `${Deno.cwd()}/src/interactions`; - Logger.debug(`Loading interactions from "${dir}"...`); + Logger.debug(`Loading interactions from "${InteractionDispatcher._interactionsDir}"...`); // Make sure the interactions directory exists - if(!folderExists(dir)) { - Logger.warning(`"${dir}" does not exist, no interactions to load`); + if(!await new Folder(InteractionDispatcher._interactionsDir).exists()) { + Logger.warning(`"${InteractionDispatcher._interactionsDir}" does not exist, no interactions to load`); return; } // Get a list of all files - const files = await Deno.readDir(dir); + const files = await Deno.readDir(InteractionDispatcher._interactionsDir); // Load all interactions const promiseQueue: Promise[] = []; for await(const file of files) { - if(!isTs(file.name)) { + if(new File(`${InteractionDispatcher._interactionsDir}/${file.name}`).ext() === 'ts') { Logger.debug(`File "${file.name}" is not a TS file, skipping...`); continue; } // Import each file as a module Logger.debug(`Loading "${file.name}"...`); - const module = await import(`file:///${dir}/${file.name}`); + const module = await import(`file:///${InteractionDispatcher._interactionsDir}/${file.name}`); // Make sure module has a "config" exposed if(!('config' in module)) { diff --git a/filesystem/file.ts b/filesystem/file.ts new file mode 100644 index 00000000..1e927c01 --- /dev/null +++ b/filesystem/file.ts @@ -0,0 +1,30 @@ +export class File { + public constructor( + private readonly path: string + ) { + } + + public async create(): Promise { + await Deno.create(this.path); + } + + public async exists(): Promise { + try { + const target = await Deno.stat(this.path); + return target.isFile; + } catch(e) { + if(e instanceof Deno.errors.NotFound) return false; + throw e; + } + } + + public async delete(): Promise { + await Deno.remove(this.path); + } + + public ext(): string { + const pos = this.path.lastIndexOf("."); + if(pos < 1) return ''; + return this.path.slice(pos + 1); + } +} diff --git a/filesystem/folder.ts b/filesystem/folder.ts new file mode 100644 index 00000000..c8698d01 --- /dev/null +++ b/filesystem/folder.ts @@ -0,0 +1,16 @@ +export class Folder { + public constructor( + private readonly path: string + ) { + } + + public async exists(): Promise { + try { + const target = await Deno.stat(this.path); + return target.isDirectory; + } catch(e) { + if(e instanceof Deno.errors.NotFound) return false; + throw e; + } + } +} diff --git a/logging/logger.ts b/logging/logger.ts index 74279b16..86d44a89 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -1,5 +1,5 @@ -import { Time } from "../common/time.ts"; -import { Configure } from "../common/configure.ts"; +import { Time } from "../utility/time.ts"; +import { Configure } from "../core/configure.ts"; import { cyan, yellow, red, magenta, bold } from "https://deno.land/std@0.117.0/fmt/colors.ts"; export class Logger { diff --git a/tests/common/configure.test.ts b/tests/common/configure.test.ts index 62372443..20549d4a 100644 --- a/tests/common/configure.test.ts +++ b/tests/common/configure.test.ts @@ -1,5 +1,5 @@ import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { Configure } from "../../common/configure.ts"; +import { Configure } from "../../core/configure.ts"; Deno.test("Configure Test", async (t) => { // Add a test variable and test against it diff --git a/tests/util/inflector.test.ts b/tests/util/inflector.test.ts index d018b459..414f6446 100644 --- a/tests/util/inflector.test.ts +++ b/tests/util/inflector.test.ts @@ -1,4 +1,4 @@ -import { Inflector } from "../../util/inflector.ts"; +import { Inflector } from "../../utility/inflector.ts"; import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; Deno.test("Inflector Test", async (t) => { diff --git a/util/folder-exists.ts b/util/folder-exists.ts deleted file mode 100644 index fe79b389..00000000 --- a/util/folder-exists.ts +++ /dev/null @@ -1,9 +0,0 @@ -export async function folderExists(path: string): Promise { - try { - const target = await Deno.stat(path); - return target.isDirectory; - } catch(e) { - if(e instanceof Deno.errors.NotFound) return false; - throw e; - } -} diff --git a/util/is-ts.ts b/util/is-ts.ts deleted file mode 100644 index eade59b9..00000000 --- a/util/is-ts.ts +++ /dev/null @@ -1,5 +0,0 @@ -export function isTs(name: string): boolean { - const pos = name.lastIndexOf("."); - if(pos < 1) return false; - return name.slice(pos + 1) === 'ts'; -} diff --git a/util/tokenizer.ts b/util/tokenizer.ts deleted file mode 100644 index e709eed0..00000000 --- a/util/tokenizer.ts +++ /dev/null @@ -1,10 +0,0 @@ -export function tokenizer(input: string, limit = 3) { - const tokens = input.split(" "); - if(tokens.length > limit) { - let ret = tokens.splice(0, limit); - ret.push(tokens.join(" ")); - return ret; - } - - return tokens; -} diff --git a/util/check-source.ts b/utility/check-source.ts similarity index 88% rename from util/check-source.ts rename to utility/check-source.ts index 076ffc1e..652459fa 100644 --- a/util/check-source.ts +++ b/utility/check-source.ts @@ -1,4 +1,5 @@ import { Logger } from "../logging/logger.ts"; +import { File } from "../filesystem/file.ts"; export interface ExclusionConfig { directories?: string[]; @@ -18,7 +19,7 @@ export class CheckSource { // Get list of files await this.getFiles(this.path); - // Checkk all files found + // Check all files found Logger.info(`Checking "${this.files.length}" files...`); await this.checkFiles(); @@ -53,7 +54,7 @@ export class CheckSource { Logger.debug(`Skipping excluded file "${path}/${entry.name}"...`); continue; } - if(!this.isTs(entry.name)) { + if(new File(`${path}/${entry.name}`).ext() !== 'ts') { Logger.debug(`Skipping non-ts file...`); continue; } @@ -86,15 +87,4 @@ export class CheckSource { } } } - - /** - * Checks whether the file is a ".ts" file - * - * @returns boolean - */ - private isTs(name: string): boolean { - const pos = name.lastIndexOf("."); - if(pos < 1) return false; - return name.slice(pos + 1) === 'ts'; - } } diff --git a/common/cron.ts b/utility/cron.ts similarity index 100% rename from common/cron.ts rename to utility/cron.ts diff --git a/util/inflector.ts b/utility/inflector.ts similarity index 97% rename from util/inflector.ts rename to utility/inflector.ts index 7419db06..4bf088ba 100644 --- a/util/inflector.ts +++ b/utility/inflector.ts @@ -14,7 +14,7 @@ export class Inflector { /** * Return input string with first character lowercased. - * + * * @param input */ public static lcfirst(input: string): string { @@ -23,7 +23,7 @@ export class Inflector { /** * Turn a string into PascalCase. - * + * * @param input */ public static pascalize(input: string, delimiter: string = '_'): string { @@ -35,7 +35,7 @@ export class Inflector { /** * Return the input lower_case_delimited_string as "A Human Readable String". * (Underscores are replaced by spaces and capitalized following words.) - * + * * @param input * @param delimiter */ @@ -43,12 +43,12 @@ export class Inflector { // Split our string into tokens const tokens: string[] = input .split(delimiter); - + // Uppercase each of the tokens for(let i = 0; i < tokens.length; i++) { tokens[i] = Inflector.ucfirst(tokens[i]); } - + // Join tokens into a string and return return tokens.join(' '); } diff --git a/util/raise.ts b/utility/raise.ts similarity index 97% rename from util/raise.ts rename to utility/raise.ts index e36f3a30..3bb59659 100644 --- a/util/raise.ts +++ b/utility/raise.ts @@ -1,6 +1,6 @@ /** * Utility function that literally just throws an error - * + * * @param err */ export function raise(err: string): never { diff --git a/utility/text.ts b/utility/text.ts new file mode 100644 index 00000000..3000238c --- /dev/null +++ b/utility/text.ts @@ -0,0 +1,25 @@ +export class Text { + /** + * Generate unique identifiers as per RFC-4122. + */ + public static uuid(): string { + return crypto.randomUUID(); + } + + /** + * Tokenize a string into an array of strings. + * + * @param input + * @param limit + */ + public static tokenize(input: string, limit = 3): string[] { + const tokens = input.split(" "); + if(tokens.length > limit) { + let ret = tokens.splice(0, limit); + ret.push(tokens.join(" ")); + return ret; + } + + return tokens; + } +} diff --git a/util/time-string.ts b/utility/time-string.ts similarity index 100% rename from util/time-string.ts rename to utility/time-string.ts diff --git a/common/time.ts b/utility/time.ts similarity index 96% rename from common/time.ts rename to utility/time.ts index a1376bee..0bdc1eaa 100644 --- a/common/time.ts +++ b/utility/time.ts @@ -1,6 +1,6 @@ import { time as timets } from "https://denopkg.com/burhanahmeed/time.ts@v2.0.1/mod.ts"; import { format as formatter } from "https://cdn.deno.land/std/versions/0.77.0/raw/datetime/mod.ts"; -import { T } from "../util/time-string.ts"; +import { T } from "./time-string.ts"; export class Time { private readonly time; diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index de34721c..a3c3cdc4 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -1,9 +1,9 @@ import { Logger } from "../../logging/logger.ts"; -import { Inflector } from "../../util/inflector.ts"; +import { Inflector } from "../../utility/inflector.ts"; import { Handlebars } from "../renderers/handlebars.ts"; import { ResponseBuilder } from "../http/response-builder.ts"; import { Request } from "../http/request.ts"; -import { raise } from "../../util/raise.ts"; +import { raise } from "../../utility/raise.ts"; import { Component } from "./component.ts"; import { Registry } from "../registry/registry.ts"; import { compress as compressBrotli } from "https://deno.land/x/brotli@v0.1.4/mod.ts"; @@ -106,7 +106,7 @@ export class Controller { * @returns Promise */ public async render(): Promise { - let body = ''; + let body: string|Uint8Array = ''; let canCompress = true; switch(this.getResponse().getHeaderLine('Content-Type').toLowerCase()) { case 'application/json': @@ -118,7 +118,7 @@ export class Controller { case 'text/html': const controller = Inflector.lcfirst(this.getRequest().getRoute().getController()); const action = this.getRequest().getRoute().getAction(); - body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars); + body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars) ?? raise('Could not render handlebars'); } // Check if we can compress with Brotli diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts index 7cb1cc3c..62ade900 100644 --- a/webserver/http/response-builder.ts +++ b/webserver/http/response-builder.ts @@ -1,5 +1,5 @@ import { StatusCodes } from "./status-codes.ts"; -import { T as TimeString } from "../../util/time-string.ts"; +import { T as TimeString } from "../../utility/time-string.ts"; interface ResponseHeader { [key: string]: string; diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index 1a54f693..c27c8eb0 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -1,6 +1,6 @@ import { default as hbs } from "https://jspm.dev/handlebars@4.7.6"; import { Logger } from "../../logging/logger.ts"; -import { raise } from "../../util/raise.ts"; +import { raise } from "../../utility/raise.ts"; import { ViewVariable } from "../controller/controller.ts"; interface CacheItem { diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 0c7fa044..405e78f6 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -1,13 +1,13 @@ import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts"; import { pathToRegexp } from "../pathToRegexp.ts"; -import { Inflector } from "../../util/inflector.ts"; +import { Inflector } from "../../utility/inflector.ts"; import { Logger } from "../../logging/logger.ts"; import { Request as ChompRequest, RequestParameters } from "../http/request.ts"; import { StatusCodes } from "../http/status-codes.ts"; import { Route as ChompRoute } from "./route.ts"; import { Controller } from "../controller/controller.ts"; import { Registry } from "../registry/registry.ts"; -import { raise } from "../../util/raise.ts"; +import { raise } from "../../utility/raise.ts"; interface Route { path: string; diff --git a/websocket/authenticator.ts b/websocket/authenticator.ts index 80321461..e92fbc1f 100644 --- a/websocket/authenticator.ts +++ b/websocket/authenticator.ts @@ -1,5 +1,5 @@ import { Logger } from "../logging/logger.ts"; -import { Configure } from "../common/configure.ts"; +import { Configure } from "../core/configure.ts"; export class Authenticator { /** diff --git a/websocket/websocket.ts b/websocket/websocket.ts index 2464e9c7..98a3ce53 100644 --- a/websocket/websocket.ts +++ b/websocket/websocket.ts @@ -2,7 +2,7 @@ import { WebSocketServer, WebSocketAcceptedClient } from "https://deno.land/x/we import { Logger } from "../logging/logger.ts"; import { Events } from "./events.ts"; import { Authenticator } from "./authenticator.ts"; -import { Configure } from "../common/configure.ts"; +import { Configure } from "../core/configure.ts"; export class Websocket { private readonly port: number = 80; From 6ddfa0f1b0ba4665b1d4d4d62afdc99bfa9084f7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 3 Aug 2023 12:53:48 +0200 Subject: [PATCH 105/379] Fix forgotten "." in extention checkers --- discord/dispatchers/event.ts | 2 +- discord/dispatchers/interaction.ts | 2 +- utility/check-source.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/discord/dispatchers/event.ts b/discord/dispatchers/event.ts index cb826a12..779a8768 100644 --- a/discord/dispatchers/event.ts +++ b/discord/dispatchers/event.ts @@ -102,7 +102,7 @@ export class EventDispatcher { // Load all interactions const promiseQueue: Promise[] = []; for await(const file of files) { - if(new File(`${dir}/${file.name}`).ext() === 'ts') { + if(new File(`${dir}/${file.name}`).ext() === '.ts') { Logger.debug(`File "${file.name}" is not a TS file, skipping...`); continue; } diff --git a/discord/dispatchers/interaction.ts b/discord/dispatchers/interaction.ts index eba8b3be..b204cf48 100644 --- a/discord/dispatchers/interaction.ts +++ b/discord/dispatchers/interaction.ts @@ -113,7 +113,7 @@ export class InteractionDispatcher { // Load all interactions const promiseQueue: Promise[] = []; for await(const file of files) { - if(new File(`${InteractionDispatcher._interactionsDir}/${file.name}`).ext() === 'ts') { + if(new File(`${InteractionDispatcher._interactionsDir}/${file.name}`).ext() === '.ts') { Logger.debug(`File "${file.name}" is not a TS file, skipping...`); continue; } diff --git a/utility/check-source.ts b/utility/check-source.ts index 652459fa..53bf1f7f 100644 --- a/utility/check-source.ts +++ b/utility/check-source.ts @@ -54,7 +54,7 @@ export class CheckSource { Logger.debug(`Skipping excluded file "${path}/${entry.name}"...`); continue; } - if(new File(`${path}/${entry.name}`).ext() !== 'ts') { + if(new File(`${path}/${entry.name}`).ext() !== '.ts') { Logger.debug(`Skipping non-ts file...`); continue; } From 4770d002761b10e1fb909a999323ffc8fb0964b4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 16 Aug 2023 19:30:21 +0200 Subject: [PATCH 106/379] Fix wrong event dispatch --- discord/discord.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/discord.ts b/discord/discord.ts index 71936b8b..7d491bc7 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -94,7 +94,7 @@ export class Discord { EventDispatcher.dispatch('GuildMemberUpdate', { member: member, user: user }); }, guildUpdate(_bot, guild) { - EventDispatcher.dispatch('InteractionCreate', guild); + EventDispatcher.dispatch('GuildUpdate', guild); }, integrationCreate(_bot, integration) { EventDispatcher.dispatch('IntegrationCreate', integration); From 4c4e347e47788ff883446785624b79d732bdc930 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 20 Aug 2023 23:39:26 +0200 Subject: [PATCH 107/379] Allow turning strings into camelCase --- utility/inflector.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/utility/inflector.ts b/utility/inflector.ts index 4bf088ba..b5c272df 100644 --- a/utility/inflector.ts +++ b/utility/inflector.ts @@ -32,6 +32,16 @@ export class Inflector { .replaceAll(' ', ''); } + /** + * Turn a string into camelCase + * + * @param input + * @param delimiter Optional delimiter by which to split the string + */ + public static camelize(input: string, delimiter: string = '_'): string { + return this.lcfirst(this.pascalize(input, delimiter)); + } + /** * Return the input lower_case_delimited_string as "A Human Readable String". * (Underscores are replaced by spaces and capitalized following words.) From 895299719c9073ab93a9c7c3d3b8282ea3cdfada Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 20 Aug 2023 23:41:38 +0200 Subject: [PATCH 108/379] Do a bit of refactoring --- utility/inflector.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utility/inflector.ts b/utility/inflector.ts index b5c272df..489b80e5 100644 --- a/utility/inflector.ts +++ b/utility/inflector.ts @@ -25,9 +25,10 @@ export class Inflector { * Turn a string into PascalCase. * * @param input + * @param delimiter Optional delimiter by which to split the string */ public static pascalize(input: string, delimiter: string = '_'): string { - return Inflector + return this .humanize(input, delimiter) .replaceAll(' ', ''); } @@ -56,7 +57,7 @@ export class Inflector { // Uppercase each of the tokens for(let i = 0; i < tokens.length; i++) { - tokens[i] = Inflector.ucfirst(tokens[i]); + tokens[i] = this.ucfirst(tokens[i]); } // Join tokens into a string and return From 8383273a5f84b3a297b469a8eb85453067f2cab8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 27 Aug 2023 23:46:48 +0200 Subject: [PATCH 109/379] Fix message --- logging/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging/logger.ts b/logging/logger.ts index 86d44a89..63d15bec 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -67,7 +67,7 @@ export class Logger { * @returns void */ public static trace(stacktrace: any): void { - Logger.warning('Use of Logger#stack is deprecated, please pass trace to Logger#error instead.'); + Logger.warning('Use of Logger#trace is deprecated, please pass trace to Logger#error instead.'); console.error(stacktrace); } From 053668344e2d519ac84d0a6a8002c22289386b39 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 27 Aug 2023 23:47:06 +0200 Subject: [PATCH 110/379] Add class for logging into InfluxDB --- communication/influxdb.ts | 153 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 communication/influxdb.ts diff --git a/communication/influxdb.ts b/communication/influxdb.ts new file mode 100644 index 00000000..02deda2d --- /dev/null +++ b/communication/influxdb.ts @@ -0,0 +1,153 @@ +import { Logger } from "../logging/logger.ts"; + +enum Precision { + s, + ms, + us, + ns, +} + +interface Api { + url: string; + auth: string; + precision: Precision; +} + +export class InfluxDB { + private _api: Api; + + public constructor( + private readonly url: string, + private readonly token: string, + ) { + } + + public setApi(org: string, bucket: string, precision: Precision = Precision.us): this { + this._api = { + url: `${this.url}/api/v2/write?org=${org}&bucket=${bucket}&precision=${Precision[precision]}`, + auth: `Token ${this.token}`, + precision: precision, + }; + + return this; + } + + /** + * Write our datapoint to InfluxDB + * + * @param point + */ + public async write(point: Point): Promise { + // Convert point to Line Protocol entry + const line = point.toLine(this._api.precision); + + // Write line to InfluxDB + try { + const resp = await fetch(this._api.url, { + headers: { + Authorization: this._api.auth, + 'Content-Type': 'text/plain', + }, + method: 'POST', + body: line, + }); + return resp.ok; + } catch(e) { + Logger.error(`Could not write point to InfluxDB`, e.stack); + return false; + } + } +} + +export class Point { + private _tags: Map = new Map(); + private _fields: Map = new Map(); + private _timestamp: Date|number = 0; + + public constructor( + private readonly measurement: string, + ) { + } + + /** + * Add a tag to our point + * + * @param key + * @param value + */ + public addTag(key: string, value: string): this { + this._tags.set(key, value); + return this; + } + + /** + * Add a field to our point + * + * @param key + * @param value + */ + public addField(key: string, value: string|number): this { + this._fields.set(key, value); + return this; + } + + /** + * Set our timestamp for the point. + * Can be either a date or a number. + * In the case that this is a number, it must be in the correct precision units. + * + * @param ts + */ + public setTimestamp(ts: Date|number): this { + this._timestamp = ts; + return this; + } + + public toLine(precision: Precision = Precision.us): string { + // Start off with a blank string + let line = ''; + + // Set the measurement + line += this.measurement; + + // Add all tags + for(const [key, value] of this._tags.entries()) { + line += `,${key}=${value}`; + } + + // Add separator before fieldset + line += ' '; + + // Add all fields + const entries = []; + for(const [key, value] of this._fields.entries()) { + entries.push(`${key}=${value}`); + } + line += entries.join(','); + + // Add timestamp + let ts = 0; + if(this._timestamp instanceof Date) { + ts = this._timestamp.getTime(); + switch(precision) { + case Precision.s: + ts = Math.trunc(ts / 1_000); + break; + case Precision.ms: + break; + case Precision.us: + ts = ts * 1_000; + break; + case Precision.ns: + ts = ts * 1_000_000; + break; + } + } else { + ts = this._timestamp; + } + line += ` ${ts}`; + + // Return our final line + return line; + } +} From 77d2d60d99b8783c7b0b382e6275fd0a8022050b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 28 Aug 2023 00:25:02 +0200 Subject: [PATCH 111/379] export enum --- communication/influxdb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/influxdb.ts b/communication/influxdb.ts index 02deda2d..abe905f7 100644 --- a/communication/influxdb.ts +++ b/communication/influxdb.ts @@ -1,6 +1,6 @@ import { Logger } from "../logging/logger.ts"; -enum Precision { +export enum Precision { s, ms, us, From 6848860f45371a966401256c261ab44eb41d4c77 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 5 Sep 2023 23:55:18 +0200 Subject: [PATCH 112/379] Fix some bugs with highlighting and non-brotli accepting requests --- webserver/controller/controller.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index a3c3cdc4..19b4c709 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -47,7 +47,7 @@ export class Controller { * * @protected */ - protected getRequest(): typeof this.request { + protected getRequest(): Request { return this.request; } @@ -56,7 +56,7 @@ export class Controller { * * @protected */ - protected getResponse(): typeof this._response { + protected getResponse(): ResponseBuilder { return this._response; } @@ -123,7 +123,7 @@ export class Controller { // Check if we can compress with Brotli // TODO: Hope that Deno will make this obsolete. - if(this.getRequest().getHeaders().get('accept-encoding').includes('br') && canCompress && body.length > 1024) { + if(this.getRequest().getHeaders().get('accept-encoding')?.includes('br') && canCompress && body.length > 1024) { Logger.debug(`Compressing body with brotli: ${body.length}-bytes`); body = compressBrotli(new TextEncoder().encode(body)); Logger.debug(`Compressed body with brotli: ${body.length}-bytes`); From c9823450d12093f1c1ade28bb87973f371b80354 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 6 Sep 2023 14:19:08 +0200 Subject: [PATCH 113/379] Fix some bugs in highlighting and allow Query parameters to be obtained from the url --- webserver/http/request.ts | 28 ++++++++++++++++++++-------- webserver/routing/router.ts | 25 ++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/webserver/http/request.ts b/webserver/http/request.ts index 51e13107..61ec60fb 100644 --- a/webserver/http/request.ts +++ b/webserver/http/request.ts @@ -4,6 +4,10 @@ export interface RequestParameters { [name: string]: string; } +export interface QueryParameters { + [name: string]: string; +} + export class Request { constructor( private readonly url: string, @@ -12,29 +16,37 @@ export class Request { private readonly headers: Headers, private readonly body: string, private readonly params: RequestParameters, + private readonly query: QueryParameters, private readonly auth: string, private readonly ip: string|null = null, ) { } - public getUrl(): typeof this.url { return this.url; } + public getUrl(): string { return this.url; } - public getMethod(): typeof this.method { return this.method; } + public getMethod(): string { return this.method; } - public getRoute(): typeof this.route { return this.route; } + public getRoute(): Route { return this.route; } - public getHeaders(): typeof this.headers { return this.headers ;} + public getHeaders(): Headers { return this.headers ;} - public getBody(): typeof this.body { return this.body; } + public getBody(): string { return this.body; } - public getParams(): typeof this.params { return this.params; } + public getParams(): RequestParameters { return this.params; } public getParam(name: string): string|null { if(name in this.params) return this.params[name]; return null; } + + public getQueryParams(): QueryParameters { return this.query; } + + public getQuery(name: string): string|null { + if(name in this.query) return this.query[name]; + return null; + } - public getAuth(): typeof this.auth { return this.auth; } + public getAuth(): string { return this.auth; } - public getIp(): typeof this.ip { return this.ip; } + public getIp(): string|null { return this.ip; } } diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 405e78f6..f1931b0e 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -2,7 +2,7 @@ import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts" import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../utility/inflector.ts"; import { Logger } from "../../logging/logger.ts"; -import { Request as ChompRequest, RequestParameters } from "../http/request.ts"; +import {QueryParameters, Request as ChompRequest, RequestParameters} from "../http/request.ts"; import { StatusCodes } from "../http/status-codes.ts"; import { Route as ChompRoute } from "./route.ts"; import { Controller } from "../controller/controller.ts"; @@ -33,6 +33,9 @@ export class Router { .replace("http://", "") .replace("https://", ""); if(host !== null) path = path.replace(host, ""); + + // Escape query params + path = path.replace("?", "%3F"); // Loop over each route // Check if it is the right method @@ -81,9 +84,12 @@ export class Router { request.headers, await Router.getBody(request), await Router.getParams(route.route, route.path), + await Router.getQuery(route.path), Router.getAuth(request), clientIp ); + + console.log(req); // Import and cache controller file if need be if(!Registry.has(req.getRoute().getController())) { @@ -156,12 +162,29 @@ export class Router { * @returns Promise<{ [key: string]: string }> */ public static async getParams(route: ChompRoute, path: string): Promise { + // Strip off query parameters + path = path.split("%3F"); + path = path[0]; + const keys: any[] = []; const r = pathToRegexp(route.getPath(), keys).exec(path) || []; return keys.reduce((acc, key, i) => ({ [key.name]: r[i + 1], ...acc }), {}); } + /** + * Get the query parameters for the given route + * + * @param path + * @returns Promise + */ + public static async getQuery(path: string): Promise { + path = path.split("%3F"); + path = path[1]; + const params = new URLSearchParams(path); + return Object.fromEntries(params.entries()); + } + /** * Get the body from the request * From c98ad31c96b41c619690c546eb6e5e2b82da24df Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 6 Sep 2023 14:48:39 +0200 Subject: [PATCH 114/379] Remove console log --- webserver/routing/router.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index f1931b0e..b0eec28e 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -88,8 +88,6 @@ export class Router { Router.getAuth(request), clientIp ); - - console.log(req); // Import and cache controller file if need be if(!Registry.has(req.getRoute().getController())) { From d4ae9a4fde56c353ae88d87a2740b27d608d7619 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 7 Sep 2023 18:48:04 +0200 Subject: [PATCH 115/379] Allow octet-streams --- webserver/controller/controller.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 19b4c709..f58c5ec7 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -119,6 +119,10 @@ export class Controller { const controller = Inflector.lcfirst(this.getRequest().getRoute().getController()); const action = this.getRequest().getRoute().getAction(); body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars) ?? raise('Could not render handlebars'); + break; + case 'application/octet-stream': + body = this._vars['data'] as Uint8Array; + break; } // Check if we can compress with Brotli From 28a358ffff6132c334916b4364d9689fa309d05f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 7 Sep 2023 18:48:15 +0200 Subject: [PATCH 116/379] Allow reading files --- filesystem/file.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/filesystem/file.ts b/filesystem/file.ts index 1e927c01..b67452bf 100644 --- a/filesystem/file.ts +++ b/filesystem/file.ts @@ -1,4 +1,5 @@ export class File { + public constructor( private readonly path: string ) { @@ -27,4 +28,12 @@ export class File { if(pos < 1) return ''; return this.path.slice(pos + 1); } + + public async readTextFile() { + return await Deno.readTextFile(this.path); + } + + public async readFile() { + return await Deno.readFile(this.path); + } } From d75b114bf4886b369ccdc1c4b97f2ecc0031aa09 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 13 Sep 2023 12:08:02 +0200 Subject: [PATCH 117/379] Make logger methods overrideable by app. --- logging/logger.ts | 97 ++++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 40 deletions(-) diff --git a/logging/logger.ts b/logging/logger.ts index 63d15bec..21836cef 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -2,32 +2,18 @@ import { Time } from "../utility/time.ts"; import { Configure } from "../core/configure.ts"; import { cyan, yellow, red, magenta, bold } from "https://deno.land/std@0.117.0/fmt/colors.ts"; -export class Logger { - /** - * Write an info message to the console - * - * @param message The message to write - * @returns void - */ - public static info(message: string): void { console.log(`[${Logger.time()}] ${cyan('INFO')} > ${message}`); } - - /** - * Write a warning message to the console - * - * @param message The message to write - * @returns void - */ - public static warning(message: string): void { console.error(`[${Logger.time()}] ${yellow('WARN')} > ${message}`); } +type LogLevels = "info"|"warning"|"error"|"debug"; +type Handlers = { + info: (message: string) => any; + warning: (message: string) => any; + error: (message: string, stack:string|null = null) => any; + debug: (message: string) => any; +}; - /** - * Write an error message to the console. - * If the "error_log" Configure item is set, will also write to file. - * - * @param message The message to write - * @param stack Optional stacktrace - * @returns void - */ - public static error(message: string, stack: string|null = null): void { +const handlers: Handlers = { + info: (message: string): void => { console.log(`[${Logger.time()}] ${cyan('INFO')} > ${message}`); }, + warning: (message: string): void => { console.error(`[${Logger.time()}] ${yellow('WARN')} > ${message}`); }, + error: (message: string, stack:string|null = null): void => { // Get current time const now = Logger.time(); @@ -47,36 +33,67 @@ export class Logger { let output = `[${now}] ${red(bold('ERROR'))} > ${message}`; if(stack) output += `\r\n${stack}`; console.error(output); + }, + debug: (message: string): void => { + if(Deno.env.get('DEBUG') == "true" || Configure.get('debug', false)) { + console.log(`[${Logger.time()}] ${magenta('DEBUG')} > ${message}`); + } } +} + +export class Logger { + private static _handlers: Handlers = handlers; /** - * Write a debug message to the console - * Only shows up when the "DEBUG" env is set to truthy + * Override a handler app-wide. + * + * @param level {LogLevels} + * @param handler {any} + */ + public static setHandler(level: LogLevels, handler: any): void { Logger._handlers[level] = handler; } + + /** + * Write an info message to the console * - * @param message The message to write - * @returns void + * @param {string} message The message to write + * @returns {void} */ - public static debug(message: string): void { - if(Deno.env.get('DEBUG') == "true" || Configure.get('debug', false)) console.log(`[${Logger.time()}] ${magenta('DEBUG')} > ${message}`); - } + public static info(message: string): void { Logger._handlers['info'](message) } /** - * Write a stacktrace to the console + * Write a warning message to the console * - * @param stacktrace The stacktrace - * @returns void + * @param {string} message The message to write + * @returns {void} */ - public static trace(stacktrace: any): void { - Logger.warning('Use of Logger#trace is deprecated, please pass trace to Logger#error instead.'); - console.error(stacktrace); - } + public static warning(message: string): void { Logger._handlers['warning'](message) } + + /** + * Write an error message to the console. + * If the "error_log" Configure item is set, will also write to file. + * + * @param {string} message The message to write + * @param {string|null} stack Optional stacktrace + * @returns {void} + */ + public static error(message: string, stack: string|null = null): void { Logger._handlers['error'](message, stack); } + + /** + * Write a debug message to the console + * Only shows up when the "DEBUG" env is set to truthy + * + * @param {string} message The message to write + * @returns {void} + */ + public static debug(message: string): void { Logger._handlers['debug'](message); } /** * Return the current time in format. * Configurable using the "logger.timeformat" key. * Defaults to "yyyy/MM/dd HH:mm:ss" (2020/11/28 20:50:30) + * https://github.com/denoland/deno_std/tree/0.77.0/datetime#datetime * - * @returns string The formatted time + * @returns {string} The formatted time */ private static time(): string { return new Time().format(Configure.get('logger.timeformat', 'yyyy/MM/dd HH:mm:ss')); From 44b3961aee240120c339d3c1c89f4575d2a349b0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 4 Oct 2023 11:58:15 +0200 Subject: [PATCH 118/379] Fix minor error --- logging/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging/logger.ts b/logging/logger.ts index 21836cef..bca15407 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -6,7 +6,7 @@ type LogLevels = "info"|"warning"|"error"|"debug"; type Handlers = { info: (message: string) => any; warning: (message: string) => any; - error: (message: string, stack:string|null = null) => any; + error: (message: string, stack: string|null) => any; debug: (message: string) => any; }; From a0942d4051a8ae2ec9b0b05fe5a3b5269f5b4213 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 4 Oct 2023 13:09:44 +0200 Subject: [PATCH 119/379] Update the way Interaction configs are made and handled --- discord/dispatchers/interaction.ts | 140 +------------------ discord/interaction/builder.ts | 159 ++++++++++++++++++++++ discord/interaction/dispatcher.ts | 163 +++++++++++++++++++++++ discord/{ => interaction}/interaction.ts | 11 +- 4 files changed, 332 insertions(+), 141 deletions(-) create mode 100644 discord/interaction/builder.ts create mode 100644 discord/interaction/dispatcher.ts rename discord/{ => interaction}/interaction.ts (75%) diff --git a/discord/dispatchers/interaction.ts b/discord/dispatchers/interaction.ts index b204cf48..ae8734da 100644 --- a/discord/dispatchers/interaction.ts +++ b/discord/dispatchers/interaction.ts @@ -1,139 +1 @@ -import {ApplicationCommandOption, ApplicationCommandTypes} from "https://deno.land/x/discordeno@13.0.0/mod.ts"; -import { Discord } from "../discord.ts"; -import { Logger } from "../../logging/logger.ts"; -import { File } from "../../filesystem/file.ts"; -import { Folder } from "../../filesystem/folder.ts"; -import { Inflector } from "../../utility/inflector.ts"; - -export interface InteractionConfig { - name: string; - description: string; - type: ApplicationCommandTypes; - options?: ApplicationCommandOption[]; - handler: string; -} - -export class InteractionDispatcher { - private static _interactionsDir = `${Deno.cwd()}/src/interactions`; - private static list: InteractionConfig[] = []; - private static handlers: any = {}; - - /** - * Return the complete list of interactions - * - * @returns IInteraction[] - */ - public static getInteractions() { return InteractionDispatcher.list; } - - /** - * Find an Interaction by name - * - * @param name - * @returns InteractionConfig|undefined - */ - public static getHandler(name: string): InteractionConfig|undefined { - return InteractionDispatcher.list.find((interaction: InteractionConfig) => interaction.name === name); - } - - /** - * Update all interactions registered to the Discord gateway - * - * @param opts - * @returns Promise - */ - public static async update(opts: any): Promise { - try { - await Discord.getBot().helpers.upsertApplicationCommands(InteractionDispatcher.getInteractions(), opts.guildId); - } catch(e) { - Logger.error(`Could not update interactions: ${e.message}`); - } - } - - /** - * Import an interaction handler and add it to the list of handlers - * - * @param interaction - * @returns Promise - */ - public static async add(interaction: InteractionConfig): Promise { - try { - // Import the interaction handler - InteractionDispatcher.handlers[interaction.handler] = await import(`file://${InteractionDispatcher._interactionsDir}/${interaction.handler}.ts`) - } catch(e) { - Logger.error(`Could not register interaction handler for "${interaction}": ${e.message}`); - return; - } - - InteractionDispatcher.list.push(interaction); - } - - /** - * Run an instance of the Interaction handler - * - * @param interaction - * @param data - * @returns Promise - */ - public static async dispatch(interaction: string, data: any = {}): Promise { - // Get the handler - const handler = InteractionDispatcher.getHandler(interaction); - if(!handler) { - Logger.debug(`Interaction "${interaction}" does not exist! (did you register it?)`); - return; - } - - // Create an instance of the handler - const controller = new InteractionDispatcher.handlers[handler.handler][`${Inflector.pascalize(interaction)}Interaction`](data); - - // Execute the handler's execute method - try { - await controller['execute'](); - } catch(e) { - Logger.error(`Could not dispatch interaction "${interaction}": "${e.message}"`, e.stack); - } - } - - /** - * Load all interactions from the required directory. - * By convention, this will be "src/interactions". - */ - public static async load(): Promise { - // Create our directory string - Logger.debug(`Loading interactions from "${InteractionDispatcher._interactionsDir}"...`); - - // Make sure the interactions directory exists - if(!await new Folder(InteractionDispatcher._interactionsDir).exists()) { - Logger.warning(`"${InteractionDispatcher._interactionsDir}" does not exist, no interactions to load`); - return; - } - - // Get a list of all files - const files = await Deno.readDir(InteractionDispatcher._interactionsDir); - - // Load all interactions - const promiseQueue: Promise[] = []; - for await(const file of files) { - if(new File(`${InteractionDispatcher._interactionsDir}/${file.name}`).ext() === '.ts') { - Logger.debug(`File "${file.name}" is not a TS file, skipping...`); - continue; - } - - // Import each file as a module - Logger.debug(`Loading "${file.name}"...`); - const module = await import(`file:///${InteractionDispatcher._interactionsDir}/${file.name}`); - - // Make sure module has a "config" exposed - if(!('config' in module)) { - Logger.warning(`Could not find config in "${interaction.name}", skipping...`); - continue; - } - - // Register in the dispatcher - module.config['handler'] = module.config.name; - promiseQueue.push(InteractionDispatcher.add(module.config)); - } - - // Wait until the promise queue has cleared - await Promise.all(promiseQueue); - } -} +export * from "../interaction/dispatcher.ts"; diff --git a/discord/interaction/builder.ts b/discord/interaction/builder.ts new file mode 100644 index 00000000..3dd1c62e --- /dev/null +++ b/discord/interaction/builder.ts @@ -0,0 +1,159 @@ +import {ApplicationCommandOptionTypes, ApplicationCommandTypes} from "../discord.ts"; + +type OptionTypes = + | ((command: InteractionSubcommandBuilder) => void) + | ((option: InteractionOptionBuilder) => void) + +type CommandTypes = keyof typeof ApplicationCommandTypes; +type CommandOptionTypes = keyof typeof ApplicationCommandOptionTypes; + +export class InteractionBuilder { + private _name: string = undefined!; + private _description: string = undefined!; + private _type: ApplicationCommandTypes = ApplicationCommandTypes.ChatInput; + private _options: Array = []; + + public setName(name: string): InteractionBuilder { + this._name = name; + + return this; + } + + public setDescription(description: string): InteractionBuilder { + this._description = description; + + return this; + } + + public setType(type: CommandTypes): InteractionBuilder { + this._type = ApplicationCommandTypes[type]; + + return this; + } + + public addSubcommand(command: (command: InteractionSubcommandBuilder) => InteractionSubcommandBuilder): InteractionBuilder { + this._options.push(command(new InteractionSubcommandBuilder())); + + return this; + } + + public addOption(option: (option: InteractionOptionBuilder) => void): InteractionBuilder { + this._options.push(option); + + return this; + } + + public toJSON() { + // Create object for our interaction + const data = { + name: this._name, + description: this._description, + type: this._type, + options: [] + }; + + // Add data for our options + for(const option of this._options) { + data.options.push(option.toJSON()); + } + + return data; + } +} + +export class InteractionSubcommandBuilder { + protected _name: string = undefined!; + protected _description: string = undefined!; + private _type: ApplicationCommandOptionTypes = ApplicationCommandOptionTypes.SubCommand; + protected _options: Array = []; + + public setName(name: string): InteractionSubcommandBuilder { + this._name = name; + + return this; + } + + public setDescription(description: string): InteractionSubcommandBuilder { + this._description = description; + + return this; + } + + public setType(type: CommandOptionTypes): InteractionSubcommandBuilder { + this._type = ApplicationCommandOptionTypes[type]; + + return this; + } + + public addOption(option: (option: InteractionOptionBuilder) => void): InteractionSubcommandBuilder { + this._options.push(option(new InteractionOptionBuilder())); + + return this; + } + + public toJSON() { + // Create object for our subcommand + const data = { + name: this._name, + description: this._description, + type: this._type, + options: [] + }; + + // Add data for our options + for(const option of this._options) { + data.options.push(option.toJSON()); + } + + return data; + } +} + +export class InteractionOptionBuilder { + private _name: string = undefined!; + private _description: string = undefined!; + private _required = false; + private _autocomplete: boolean = false; + private _type: ApplicationCommandOptionTypes = undefined!; + + public setName(name: string): InteractionOptionBuilder { + this._name = name; + + return this; + } + + public setDescription(description: string): InteractionOptionBuilder { + this._description = description; + + return this; + } + + public setType(type: CommandOptionTypes): InteractionOptionBuilder { + this._type = ApplicationCommandOptionTypes[type]; + + return this; + } + + public setRequired(required: boolean): InteractionOptionBuilder { + this._required = required; + + return this; + } + + public setAutocomplete(autocomplete: boolean): InteractionOptionBuilder { + this._autocomplete = autocomplete; + + return this; + } + + public toJSON() { + // Create object for our option + return { + name: this._name, + description: this._description, + type: this._type, + required: this._required, + autocomplete: this._autocomplete, + }; + } +} diff --git a/discord/interaction/dispatcher.ts b/discord/interaction/dispatcher.ts new file mode 100644 index 00000000..5cbd23f2 --- /dev/null +++ b/discord/interaction/dispatcher.ts @@ -0,0 +1,163 @@ +import { ApplicationCommandOption, ApplicationCommandTypes } from "https://deno.land/x/discordeno@13.0.0/mod.ts"; +import { Discord } from "../discord.ts"; +import { Logger } from "../../logging/logger.ts"; +import { File } from "../../filesystem/file.ts"; +import { Folder } from "../../filesystem/folder.ts"; +import { Inflector } from "../../utility/inflector.ts"; +import { InteractionBuilder } from "./builder.ts"; + +export interface InteractionConfig { + name: string; + description: string; + type: ApplicationCommandTypes; + options?: ApplicationCommandOption[]; + handler: string; +} + +export class InteractionDispatcher { + private static _interactionsDir = `${Deno.cwd()}/src/interactions`; + private static list: InteractionConfig[] = []; + private static handlers: any = {}; + + /** + * Return the complete list of interactions + * + * @returns IInteraction[] + */ + public static getInteractions() { return InteractionDispatcher.list; } + + /** + * Find an Interaction by name + * + * @param name + * @returns InteractionConfig|undefined + */ + public static getHandler(name: string): InteractionConfig|undefined { + return InteractionDispatcher.list.find((interaction: InteractionConfig) => interaction.name === name); + } + + /** + * Update all interactions registered to the Discord gateway + * + * @param opts + * @returns Promise + */ + public static async update(opts: any): Promise { + try { + await Discord.getBot().helpers.upsertApplicationCommands(InteractionDispatcher.getInteractions(), opts.guildId); + } catch(e) { + Logger.error(`Could not update interactions: ${e.message}`); + } + } + + /** + * Import an interaction handler and add it to the list of handlers + * + * @param interaction + * @returns Promise + */ + public static async add(interaction: InteractionConfig): Promise { + try { + // Import the interaction handler + InteractionDispatcher.handlers[interaction.handler] = await import(`file://${InteractionDispatcher._interactionsDir}/${interaction.handler}.ts`) + } catch(e) { + Logger.error(`Could not register interaction handler for "${interaction}": ${e.message}`); + return; + } + + InteractionDispatcher.list.push(interaction); + } + + /** + * Run an instance of the Interaction handler + * + * @param interaction + * @param data + * @returns Promise + */ + public static async dispatch(interaction: string, data: any = {}): Promise { + // Get the handler + const handler = InteractionDispatcher.getHandler(interaction); + if(!handler) { + Logger.debug(`Interaction "${interaction}" does not exist! (did you register it?)`); + return; + } + + // Create an instance of the handler + const controller = new InteractionDispatcher.handlers[handler.handler][`${Inflector.pascalize(interaction)}Interaction`](data); + + // Execute the handler's execute method + try { + await controller['execute'](); + } catch(e) { + Logger.error(`Could not dispatch interaction "${interaction}": "${e.message}"`, e.stack); + } + } + + /** + * Load all interactions from the required directory. + * By convention, this will be "src/interactions". + */ + public static async load(): Promise { + // Create our directory string + Logger.debug(`Loading interactions from "${InteractionDispatcher._interactionsDir}"...`); + + // Make sure the interactions directory exists + if(!await new Folder(InteractionDispatcher._interactionsDir).exists()) { + Logger.warning(`"${InteractionDispatcher._interactionsDir}" does not exist, no interactions to load`); + return; + } + + // Get a list of all files + const files = await Deno.readDir(InteractionDispatcher._interactionsDir); + + // Load all interactions + const promiseQueue: Promise[] = []; + for await(const file of files) { + if(new File(`${InteractionDispatcher._interactionsDir}/${file.name}`).ext() === '.ts') { + Logger.debug(`File "${file.name}" is not a TS file, skipping...`); + continue; + } + + // Import each file as a module + Logger.debug(`Loading "${file.name}"...`); + const module = await import(`file:///${InteractionDispatcher._interactionsDir}/${file.name}`); + + // Get the interaction name + let name = file.name.replace(".ts", ""); + name = Inflector.pascalize(name); + + // Check if the module contains the interaction class + if(!(`${name}Interaction` in module)) { + Logger.warning(`Could not find "${name}Interaction" in "${file.name}"...`); + continue; + } + + // Make sure module has a "config" exposed + if(!('config' in module)) { + Logger.warning(`Could not find config in "${interaction.name}", skipping...`); + continue; + } + + // Register in dispatcher + // TODO: Remove support for registering as object. + switch(typeof module.config) { + case 'object': { + Logger.warning(`Registering module configs as objects is deprecated. Please use the "InteractionBuilder" instead.`); + module.config['handler'] = module.config.name; + promiseQueue.push(InteractionDispatcher.add(module.config)); + break; + } + case 'function': { + const config = module.config(new InteractionBuilder()).toJSON(); + config['handler'] = config.name; + promiseQueue.push(InteractionDispatcher.add(config)); + break; + } + } + } + + // Wait until the promise queue has cleared + await Promise.all(promiseQueue); + } +} diff --git a/discord/interaction.ts b/discord/interaction/interaction.ts similarity index 75% rename from discord/interaction.ts rename to discord/interaction/interaction.ts index 5ed60eb7..949e097e 100644 --- a/discord/interaction.ts +++ b/discord/interaction/interaction.ts @@ -1,4 +1,4 @@ -import { Discord } from "./discord.ts"; +import { Discord } from "../discord.ts"; export class Interaction { protected interaction: unknown; @@ -8,13 +8,20 @@ export class Interaction { this.interaction = opts.interaction; } + /** + * Main logic for the interaction. + * + * @returns Promise + */ + public async execute?(): Promise; + /** * Respond to the interaction. * This method will automatically edit the original reply if already replied. * * @param data */ - public async respond(data: unknown): Promise { + protected async respond(data: unknown): Promise { if(!this._hasReplied) { await Discord.getBot().helpers.sendInteractionResponse( this.interaction.id, From 204ce92a0234b80ff59b8bec02624f29a997b8c4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 4 Oct 2023 13:16:13 +0200 Subject: [PATCH 120/379] Fix small bug --- discord/interaction/builder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/interaction/builder.ts b/discord/interaction/builder.ts index 3dd1c62e..facb3d0a 100644 --- a/discord/interaction/builder.ts +++ b/discord/interaction/builder.ts @@ -38,7 +38,7 @@ export class InteractionBuilder { } public addOption(option: (option: InteractionOptionBuilder) => void): InteractionBuilder { - this._options.push(option); + this._options.push(option(new InteractionOptionBuilder())); return this; } From eed7ccf212842df183b72d721bbdf8376e8d8ced Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 3 Dec 2023 23:07:58 +0100 Subject: [PATCH 121/379] Use caching when finding role by name --- discord/util/find-role-by-name.ts | 22 ++++++++++++++-------- utility/empty.ts | 11 +++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 utility/empty.ts diff --git a/discord/util/find-role-by-name.ts b/discord/util/find-role-by-name.ts index 19d69390..7dc6e081 100644 --- a/discord/util/find-role-by-name.ts +++ b/discord/util/find-role-by-name.ts @@ -1,27 +1,30 @@ -import { Discord } from "../discord.ts"; +import { Cache } from "../../core/cache.ts"; +import { Discord, Role } from "../discord.ts"; import { Logger } from "../../logging/logger.ts"; +import empty from "../../utility/empty.ts"; /** * Find a role by its name rather than ID - * TODO: (1) Create a Map that maps role names and snowflakes together (updates on event by gateway) - * TODO: (2) Lookup role name in new map (acts as cache) - * TODO: (3) Obtain role from roles list directly - * TODO: Find out return type * * @param guild * @param roleName * @returns Promise */ -export async function findRoleByName(guild: BigInt, roleName: string): Promise { +export async function findRoleByName(guild: BigInt, roleName: string, expiry: string|null = `+1 hour`): Promise { + if(!empty(expiry) && Cache.exists(`role name ${roleName}`)) { + return Cache.get(`role name ${roleName}`) as Role; + } + // Get a list of all roles for the guild - const roles = await Discord.getBot().helpers.getRoles(guild); + const roles = Discord.getBot().roles + ?? await Discord.getBot().helpers.getRoles(guild); if(!roles) { Logger.error(`Could not obtain roles for guild! (this is a bug!)`); return null; } // Find role by name - const role = roles.find((role: unknown) => role.name === roleName); + const role = roles.find((role: Role): boolean => role.name === roleName); // Check if a role was found // Return result @@ -29,5 +32,8 @@ export async function findRoleByName(guild: BigInt, roleName: string): Promise Date: Wed, 13 Dec 2023 22:39:05 +0100 Subject: [PATCH 122/379] Move `raise` function to `error` folder --- {utility => error}/raise.ts | 0 webserver/controller/controller.ts | 2 +- webserver/renderers/handlebars.ts | 2 +- webserver/routing/router.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename {utility => error}/raise.ts (100%) diff --git a/utility/raise.ts b/error/raise.ts similarity index 100% rename from utility/raise.ts rename to error/raise.ts diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index f58c5ec7..8d0f978d 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -3,7 +3,7 @@ import { Inflector } from "../../utility/inflector.ts"; import { Handlebars } from "../renderers/handlebars.ts"; import { ResponseBuilder } from "../http/response-builder.ts"; import { Request } from "../http/request.ts"; -import { raise } from "../../utility/raise.ts"; +import { raise } from "../../error/raise.ts"; import { Component } from "./component.ts"; import { Registry } from "../registry/registry.ts"; import { compress as compressBrotli } from "https://deno.land/x/brotli@v0.1.4/mod.ts"; diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index c27c8eb0..1a6f2df3 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -1,6 +1,6 @@ import { default as hbs } from "https://jspm.dev/handlebars@4.7.6"; import { Logger } from "../../logging/logger.ts"; -import { raise } from "../../utility/raise.ts"; +import { raise } from "../../error/raise.ts"; import { ViewVariable } from "../controller/controller.ts"; interface CacheItem { diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index b0eec28e..026fcb0e 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -7,7 +7,7 @@ import { StatusCodes } from "../http/status-codes.ts"; import { Route as ChompRoute } from "./route.ts"; import { Controller } from "../controller/controller.ts"; import { Registry } from "../registry/registry.ts"; -import { raise } from "../../utility/raise.ts"; +import { raise } from "../../error/raise.ts"; interface Route { path: string; From b9cd05be347a768c6d677fc03566385131086aab Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 14 Dec 2023 00:20:04 +0100 Subject: [PATCH 123/379] Update raise to quickly be able to make custom error names --- error/raise.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/error/raise.ts b/error/raise.ts index 3bb59659..e5465ef2 100644 --- a/error/raise.ts +++ b/error/raise.ts @@ -1,8 +1,17 @@ /** - * Utility function that literally just throws an error + * Utility function that literally just throws an error. + * TODO: Allow passing custom error classes for better extendability. * * @param err + * @param type */ -export function raise(err: string): never { - throw new Error(err); +export function raise(err: string, type: string|'Error' = 'Error'): never { + // Check if we want to throw a regular error + if(type === "Error") throw new Error(err); + + // Build a custom error and throw it + if(type.slice(-5).toLowerCase() !== "error") type = `${type}Error`; + const e = new Error(err); + e.name = type; + throw e; } From b2aed3ef58c3a6f93a0c019001c060b2ab925be7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 14 Dec 2023 00:24:15 +0100 Subject: [PATCH 124/379] Allow passing custom error classes --- error/raise.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/error/raise.ts b/error/raise.ts index e5465ef2..4de9dee5 100644 --- a/error/raise.ts +++ b/error/raise.ts @@ -1,14 +1,16 @@ /** * Utility function that literally just throws an error. - * TODO: Allow passing custom error classes for better extendability. * * @param err * @param type */ -export function raise(err: string, type: string|'Error' = 'Error'): never { +export function raise(err: string, type: string|Function|'Error' = 'Error'): never { // Check if we want to throw a regular error if(type === "Error") throw new Error(err); + // Check if we want to throw a specific error class + if(typeof type === "function") throw new type(err); + // Build a custom error and throw it if(type.slice(-5).toLowerCase() !== "error") type = `${type}Error`; const e = new Error(err); From 801e42e32c2aa84bb5245999fe1fcf7806d3d486 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 14 Dec 2023 15:13:05 +0100 Subject: [PATCH 125/379] Update type for bot --- discord/discord.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discord/discord.ts b/discord/discord.ts index 7d491bc7..abdcce4d 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -19,7 +19,7 @@ export interface DiscordInitOpts { } export class Discord { - protected static bot: Bot|undefined; + protected static bot: Bot|BotWithCache|undefined; protected token = ''; protected intents: any; protected botId = BigInt(0); @@ -27,7 +27,7 @@ export class Discord { /** * Return the instance of the Discord bot connection */ - public static getBot(): Bot|undefined { return Discord.bot; } + public static getBot(): Bot|BotWithCache|undefined { return Discord.bot; } public constructor(opts: DiscordInitOpts) { // Make sure required parameters are present From aeaa8664c3b328725943b31bd1f001767321c498 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 14 Dec 2023 15:20:39 +0100 Subject: [PATCH 126/379] Fix bug with role cache --- core/cache.ts | 3 ++- discord/util/find-role-by-name.ts | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index 151b6b15..2114f83d 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -44,7 +44,8 @@ export class Cache { } /** - * Check whether an item exists in the cache + * Check whether an item exists in the cache. + * This does *not* check whether the item has expired or not. * * @param key */ diff --git a/discord/util/find-role-by-name.ts b/discord/util/find-role-by-name.ts index 7dc6e081..43a5395e 100644 --- a/discord/util/find-role-by-name.ts +++ b/discord/util/find-role-by-name.ts @@ -8,10 +8,11 @@ import empty from "../../utility/empty.ts"; * * @param guild * @param roleName + * @param expiry Expiry time. Pass null to disable caching. * @returns Promise */ export async function findRoleByName(guild: BigInt, roleName: string, expiry: string|null = `+1 hour`): Promise { - if(!empty(expiry) && Cache.exists(`role name ${roleName}`)) { + if(!empty(expiry) && !Cache.expired(`role name ${roleName}`)) { return Cache.get(`role name ${roleName}`) as Role; } @@ -34,6 +35,6 @@ export async function findRoleByName(guild: BigInt, roleName: string, expiry: st } // Set the cache - Cache.set(`role name ${roleName}`, role, expiry); + if(!empty(expiry)) Cache.set(`role name ${roleName}`, role, expiry); return role; } From 1ebd6f63129432c8bd509be295ec817d6af88012 Mon Sep 17 00:00:00 2001 From: Aroop 'FinlayDaG33k' Roelofs Date: Tue, 9 Jan 2024 10:50:32 +0100 Subject: [PATCH 127/379] Update dispatcher.ts Throw error to be handled by the app instead --- discord/interaction/dispatcher.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/discord/interaction/dispatcher.ts b/discord/interaction/dispatcher.ts index 5cbd23f2..07f5e186 100644 --- a/discord/interaction/dispatcher.ts +++ b/discord/interaction/dispatcher.ts @@ -87,11 +87,7 @@ export class InteractionDispatcher { const controller = new InteractionDispatcher.handlers[handler.handler][`${Inflector.pascalize(interaction)}Interaction`](data); // Execute the handler's execute method - try { - await controller['execute'](); - } catch(e) { - Logger.error(`Could not dispatch interaction "${interaction}": "${e.message}"`, e.stack); - } + await controller['execute'](); } /** From 01fd913cbd3547e944f96deb3455ac8acbf1e38a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 15 Jan 2024 22:38:04 +0100 Subject: [PATCH 128/379] Fix bug with query parameters not properly parsing --- webserver/routing/router.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 026fcb0e..d5390a91 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -34,8 +34,8 @@ export class Router { .replace("https://", ""); if(host !== null) path = path.replace(host, ""); - // Escape query params - path = path.replace("?", "%3F"); + // Ignore query parameters + path = path.split("?", 1)[0]; // Loop over each route // Check if it is the right method @@ -84,7 +84,7 @@ export class Router { request.headers, await Router.getBody(request), await Router.getParams(route.route, route.path), - await Router.getQuery(route.path), + await Router.getQuery(request.url), Router.getAuth(request), clientIp ); @@ -177,9 +177,7 @@ export class Router { * @returns Promise */ public static async getQuery(path: string): Promise { - path = path.split("%3F"); - path = path[1]; - const params = new URLSearchParams(path); + const params = new URLSearchParams(path.split("?")[1]); return Object.fromEntries(params.entries()); } From 23bfecd941f8c98ab7f0b3d4d95967e8002f17db Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 18 Jan 2024 00:20:25 +0100 Subject: [PATCH 129/379] Update comments and add Random.float() and Random.integer() --- security/random.ts | 47 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/security/random.ts b/security/random.ts index c37bf56b..2032fb1d 100644 --- a/security/random.ts +++ b/security/random.ts @@ -1,6 +1,7 @@ export class Random { /** - * Generate random bytes + * Generate random bytes. + * These bytes are generated using the Web Crypto API, this cryptographically secure. * * @param length Amount of bytes to be generated * @returns Uint8Array @@ -12,7 +13,8 @@ export class Random { } /** - * Generate a random string + * Generate a random string. + * These strings are generated using the Web Crypto API, this cryptographically secure. * * @param length Length of the string to be generated * @returns Promise @@ -21,4 +23,45 @@ export class Random { const buf = await Random.bytes(length / 2); return Array.from(buf, (dec: number) => dec.toString(16).padStart(2, "0")).join(''); } + + /** + * Inclusively generate a random integer between min and max. + * If you want to use decimals, please use Random.float() instead. + * + * By default, these integers are **NOT** cryptographically secure (for performance reasons). + * Set the "secure" argument to "true" if you are using this for cryptographic purposes! + * + * @param min Minimum allowable integer + * @param max Maximum allowable integer + * @param secure Using this for cryptographic purposes? + */ + public static integer(min = 0, max = 1, secure = false): number { + // Strip decimals + min = Math.ceil(min); + max = Math.floor(max); + + // Generate a number using Random.float and floor that + return Math.floor(Random.float(min, max, secure)); + } + + /** + * Inclusively generate a random float between min and max. + * If you do not want to use decimals, please use Random.integer() instead. + * + * By default, these floats are **NOT** cryptographically secure (for performance reasons). + * Set the "secure" argument to "true" if you are using this for cryptographic purposes! + * + * @param min Minimum allowable float + * @param max Maximum allowable float + * @param secure Using this for cryptographic purposes? + */ + public static float(min = 0, max = 1, secure = false): number { + // Generate our randomness + const random = secure + ? crypto.getRandomValues(new Uint32Array(1))[0] / Math.pow(2, 32) + : Math.random(); + + // Limit and return + return random * (max - min + 1) + min; + } } From 1f8c6c0bca3bd66b565c699869c9c3a35977e0ff Mon Sep 17 00:00:00 2001 From: Sebastian Koczwara <44639352+sebakocz@users.noreply.github.com> Date: Thu, 18 Jan 2024 18:44:17 +0100 Subject: [PATCH 130/379] update discordeno 13 -> 18 (#9) Long overdue update to Discordeno version 18. --- discord/discord.ts | 6 +++--- discord/interaction/dispatcher.ts | 4 ++-- discord/mod.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/discord/discord.ts b/discord/discord.ts index abdcce4d..21eb5bd9 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -1,14 +1,14 @@ -import { createBot, startBot, Bot } from "https://deno.land/x/discordeno@13.0.0/mod.ts"; +import { createBot, startBot, Bot } from "https://deno.land/x/discordeno@18.0.0/mod.ts"; import { BotWithCache, enableCachePlugin, enableCacheSweepers -} from "https://deno.land/x/discordeno@13.0.0/plugins/cache/mod.ts"; +} from "https://deno.land/x/discordeno@18.0.0/plugins/cache/mod.ts"; import { EventDispatcher } from "./dispatchers/event.ts"; import { Logger } from "../logging/logger.ts"; import { InteractionDispatcher } from "./dispatchers/interaction.ts"; -export * from "https://deno.land/x/discordeno@13.0.0/mod.ts"; +export * from "https://deno.land/x/discordeno@18.0.0/mod.ts"; export interface DiscordInitOpts { token: string; diff --git a/discord/interaction/dispatcher.ts b/discord/interaction/dispatcher.ts index 07f5e186..2a46ae6d 100644 --- a/discord/interaction/dispatcher.ts +++ b/discord/interaction/dispatcher.ts @@ -1,4 +1,4 @@ -import { ApplicationCommandOption, ApplicationCommandTypes } from "https://deno.land/x/discordeno@13.0.0/mod.ts"; +import { ApplicationCommandOption, ApplicationCommandTypes } from "https://deno.land/x/discordeno@18.0.0/mod.ts"; import { Discord } from "../discord.ts"; import { Logger } from "../../logging/logger.ts"; import { File } from "../../filesystem/file.ts"; @@ -44,7 +44,7 @@ export class InteractionDispatcher { */ public static async update(opts: any): Promise { try { - await Discord.getBot().helpers.upsertApplicationCommands(InteractionDispatcher.getInteractions(), opts.guildId); + await Discord.getBot()?.helpers.upsertGuildApplicationCommands(opts.guildId, InteractionDispatcher.getInteractions()); } catch(e) { Logger.error(`Could not update interactions: ${e.message}`); } diff --git a/discord/mod.ts b/discord/mod.ts index 50e3c2bf..6da2e420 100644 --- a/discord/mod.ts +++ b/discord/mod.ts @@ -14,8 +14,8 @@ export { Intents, AuditLogEvents, ApplicationCommandFlags -} from "https://deno.land/x/discordeno@13.0.0/mod.ts"; +} from "https://deno.land/x/discordeno@18.0.0/mod.ts"; export type { DiscordEmbed -} from "https://deno.land/x/discordeno@13.0.0/mod.ts"; +} from "https://deno.land/x/discordeno@18.0.0/mod.ts"; From d9923cbfef9d3145003ad52f4fd2a8086fb24fe5 Mon Sep 17 00:00:00 2001 From: Aroop 'FinlayDaG33k' Roelofs Date: Tue, 23 Jan 2024 01:41:33 +0100 Subject: [PATCH 131/379] Update interaction.ts Fix error --- discord/interaction/interaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/interaction/interaction.ts b/discord/interaction/interaction.ts index 949e097e..ce3f36c6 100644 --- a/discord/interaction/interaction.ts +++ b/discord/interaction/interaction.ts @@ -32,7 +32,7 @@ export class Interaction { return; } - await Discord.getBot().helpers.editInteractionResponse( + await Discord.getBot().helpers.editOriginalInteractionResponse( this.interaction.token, data ); From a7c7caa6bf692e51683c4ea9463849722e7f4025 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 24 Jan 2024 15:26:10 +0100 Subject: [PATCH 132/379] Bunch of renaming and moving stuff around to make imports and updates easier --- discord/discord.ts | 16 ++++----- discord/dispatchers/interaction.ts | 1 - discord/dispatchers/mod.ts | 2 -- .../event.ts => event/dispatcher.ts} | 8 ++--- discord/event/event.ts | 3 ++ discord/interaction/builder.ts | 2 +- discord/interaction/dispatcher.ts | 2 +- discord/interaction/interaction.ts | 2 +- discord/mod.ts | 36 ++++++++++--------- discord/util/find-channel-by-name.ts | 2 +- discord/util/find-role-by-name.ts | 2 +- discord/util/mod.ts | 3 -- logging/mod.ts | 1 - mod.ts | 11 ++++++ queue/mod.ts | 1 - 15 files changed, 48 insertions(+), 44 deletions(-) delete mode 100644 discord/dispatchers/interaction.ts delete mode 100644 discord/dispatchers/mod.ts rename discord/{dispatchers/event.ts => event/dispatcher.ts} (97%) create mode 100644 discord/event/event.ts delete mode 100644 discord/util/mod.ts delete mode 100644 logging/mod.ts create mode 100644 mod.ts delete mode 100644 queue/mod.ts diff --git a/discord/discord.ts b/discord/discord.ts index 21eb5bd9..4101c047 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -1,14 +1,14 @@ -import { createBot, startBot, Bot } from "https://deno.land/x/discordeno@18.0.0/mod.ts"; -import { +import { + createBot, + startBot, + Bot, BotWithCache, enableCachePlugin, - enableCacheSweepers -} from "https://deno.land/x/discordeno@18.0.0/plugins/cache/mod.ts"; -import { EventDispatcher } from "./dispatchers/event.ts"; + enableCacheSweepers, + EventDispatcher, + InteractionDispatcher +} from "./mod.ts"; import { Logger } from "../logging/logger.ts"; -import { InteractionDispatcher } from "./dispatchers/interaction.ts"; - -export * from "https://deno.land/x/discordeno@18.0.0/mod.ts"; export interface DiscordInitOpts { token: string; diff --git a/discord/dispatchers/interaction.ts b/discord/dispatchers/interaction.ts deleted file mode 100644 index ae8734da..00000000 --- a/discord/dispatchers/interaction.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "../interaction/dispatcher.ts"; diff --git a/discord/dispatchers/mod.ts b/discord/dispatchers/mod.ts deleted file mode 100644 index 160d1e25..00000000 --- a/discord/dispatchers/mod.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./event.ts"; -export * from "./interaction.ts"; diff --git a/discord/dispatchers/event.ts b/discord/event/dispatcher.ts similarity index 97% rename from discord/dispatchers/event.ts rename to discord/event/dispatcher.ts index 779a8768..f9705175 100644 --- a/discord/dispatchers/event.ts +++ b/discord/event/dispatcher.ts @@ -8,10 +8,6 @@ interface EventConfig { handler: string; } -export interface Event { - execute(opts: unknown): Promise; -} - export class EventDispatcher { private static list: EventConfig[] = []; private static handlers: any = {}; @@ -47,7 +43,7 @@ export class EventDispatcher { // Make sure source file has required class if(!(`${event.name}Event` in handler)) throw Error(`No class named "${event.name}Event" could be found!`); - + // Register handler EventDispatcher.handlers[event.handler] = handler; } catch(e) { @@ -110,7 +106,7 @@ export class EventDispatcher { // Import the file as a module Logger.debug(`Loading "${file.name}"...`); const module = await import(`file:///${dir}/${file.name}`); - + // Make sure the file contains a valid handler const name = file.name.replace('.ts', ''); const eventName = Inflector.pascalize(name, '-'); diff --git a/discord/event/event.ts b/discord/event/event.ts new file mode 100644 index 00000000..7139a80b --- /dev/null +++ b/discord/event/event.ts @@ -0,0 +1,3 @@ +export interface Event { + execute(opts: unknown): Promise; +} diff --git a/discord/interaction/builder.ts b/discord/interaction/builder.ts index facb3d0a..e1467260 100644 --- a/discord/interaction/builder.ts +++ b/discord/interaction/builder.ts @@ -1,4 +1,4 @@ -import {ApplicationCommandOptionTypes, ApplicationCommandTypes} from "../discord.ts"; +import {ApplicationCommandOptionTypes, ApplicationCommandTypes} from "../mod.ts"; type OptionTypes = | ((command: InteractionSubcommandBuilder) => void) diff --git a/discord/interaction/dispatcher.ts b/discord/interaction/dispatcher.ts index 2a46ae6d..23967ac8 100644 --- a/discord/interaction/dispatcher.ts +++ b/discord/interaction/dispatcher.ts @@ -1,4 +1,4 @@ -import { ApplicationCommandOption, ApplicationCommandTypes } from "https://deno.land/x/discordeno@18.0.0/mod.ts"; +import { ApplicationCommandOption, ApplicationCommandTypes } from "../mod.ts"; import { Discord } from "../discord.ts"; import { Logger } from "../../logging/logger.ts"; import { File } from "../../filesystem/file.ts"; diff --git a/discord/interaction/interaction.ts b/discord/interaction/interaction.ts index ce3f36c6..94a39349 100644 --- a/discord/interaction/interaction.ts +++ b/discord/interaction/interaction.ts @@ -1,4 +1,4 @@ -import { Discord } from "../discord.ts"; +import { Discord } from "../mod.ts"; export class Interaction { protected interaction: unknown; diff --git a/discord/mod.ts b/discord/mod.ts index 6da2e420..a23365a6 100644 --- a/discord/mod.ts +++ b/discord/mod.ts @@ -1,21 +1,23 @@ -export * from "./dispatchers/mod.ts"; -export * from "./util/mod.ts"; +// Export Discordeno +export * from "https://deno.land/x/discordeno@18.0.0/mod.ts"; +export { enableCachePlugin, enableCacheSweepers } from "https://deno.land/x/discordeno@18.0.0/plugins/cache/mod.ts"; +export type { BotWithCache } from "https://deno.land/x/discordeno@18.0.0/plugins/cache/mod.ts"; -export * from "./interaction.ts"; +// Export EventDispatcher +export { EventDispatcher } from "./event/dispatcher.ts"; +export type { Event } from "./event/event.ts"; -export { - Discord, - InteractionResponseTypes, - ApplicationCommandTypes, - ApplicationCommandOptionTypes -} from "./discord.ts"; +// Export InteractionDispatcher +export { InteractionDispatcher } from "./interaction/dispatcher.ts"; +export type { InteractionConfig } from "./interaction/dispatcher.ts"; +export { Interaction } from "./interaction/interaction.ts"; + +// Export Utility functions +export { findChannelByName } from "./util/find-channel-by-name.ts"; +export { findRoleByName } from "./util/find-role-by-name.ts"; +export { snowflakeToDate } from "./util/snowflake-to-date.ts"; + +// Export Discord class +export { Discord } from "./discord.ts"; -export { - Intents, - AuditLogEvents, - ApplicationCommandFlags -} from "https://deno.land/x/discordeno@18.0.0/mod.ts"; -export type { - DiscordEmbed -} from "https://deno.land/x/discordeno@18.0.0/mod.ts"; diff --git a/discord/util/find-channel-by-name.ts b/discord/util/find-channel-by-name.ts index bc0e1889..e86c45a0 100644 --- a/discord/util/find-channel-by-name.ts +++ b/discord/util/find-channel-by-name.ts @@ -1,4 +1,4 @@ -import { Discord } from "../discord.ts"; +import { Discord } from "../mod.ts"; import { Logger } from "../../logging/logger.ts"; /** diff --git a/discord/util/find-role-by-name.ts b/discord/util/find-role-by-name.ts index 43a5395e..ca05031f 100644 --- a/discord/util/find-role-by-name.ts +++ b/discord/util/find-role-by-name.ts @@ -1,5 +1,5 @@ import { Cache } from "../../core/cache.ts"; -import { Discord, Role } from "../discord.ts"; +import { Discord, Role } from "../mod.ts"; import { Logger } from "../../logging/logger.ts"; import empty from "../../utility/empty.ts"; diff --git a/discord/util/mod.ts b/discord/util/mod.ts deleted file mode 100644 index 88fa3ce3..00000000 --- a/discord/util/mod.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { findChannelByName } from "./find-channel-by-name.ts"; -export { findRoleByName } from "./find-role-by-name.ts"; -export { snowflakeToDate } from "./snowflake-to-date.ts"; diff --git a/logging/mod.ts b/logging/mod.ts deleted file mode 100644 index 8824d1b2..00000000 --- a/logging/mod.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./logger.ts"; diff --git a/mod.ts b/mod.ts new file mode 100644 index 00000000..fbda1f53 --- /dev/null +++ b/mod.ts @@ -0,0 +1,11 @@ +/** + * These are just the exports you'll most commonly use. + * You can view the "README.md" to see what else there is! + */ +export { Cache } from "./core/cache.ts"; +export { Configure } from "./core/configure.ts"; +export { Logger } from "./logging/logger.ts"; +export { raise } from "./error/raise.ts"; +export { File } from "./filesystem/file.ts"; +export { Folder } from "./filesystem/folder.ts"; +export { CheckSource } from "./utility/check-source.ts"; diff --git a/queue/mod.ts b/queue/mod.ts deleted file mode 100644 index dfe032f0..00000000 --- a/queue/mod.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./queue.ts"; From ef3e8b2ecdc9157cd3f434e25c2bdf05e8361f79 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 24 Jan 2024 15:26:35 +0100 Subject: [PATCH 133/379] Start writing proper docs --- README.md | 27 ++++++++------------------- docs/communication.md | 3 +++ docs/core.md | 3 +++ docs/discord.md | 3 +++ docs/error.md | 3 +++ docs/filesystem.md | 3 +++ docs/getting-started.md | 33 +++++++++++++++++++++++++++++++++ docs/logging.md | 3 +++ docs/queue.md | 3 +++ docs/security.md | 3 +++ docs/utility.md | 3 +++ docs/webserver.md | 3 +++ docs/websocket.md | 3 +++ 13 files changed, 74 insertions(+), 19 deletions(-) create mode 100644 docs/communication.md create mode 100644 docs/core.md create mode 100644 docs/discord.md create mode 100644 docs/error.md create mode 100644 docs/filesystem.md create mode 100644 docs/getting-started.md create mode 100644 docs/logging.md create mode 100644 docs/queue.md create mode 100644 docs/security.md create mode 100644 docs/utility.md create mode 100644 docs/webserver.md create mode 100644 docs/websocket.md diff --git a/README.md b/README.md index 243c002c..dfe5808b 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,15 @@ # Chomp -Library of (arguably) useful Deno classes. +Library of (arguably) useful stuff. Should work just fine but comes with no warranties whatsoever. ## Usage -Add the following to your file: -```ts -import * from "https://deno.land/x/chomp/mod.ts"; -``` -That's it! -You can visit the [documentation](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what Chomp is capable off! -Someday I'll write a better usage guide. +You can read the [Getting Started](docs/getting-started.md) to see how to use Chomp. +Additionally, you can visit the [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what Chomp is capable off! +## Versioning -## Compatibility -Below a chart indicating for which Deno version this library is built and tested. -Compatibility may be more flexible, however, chances are this library may not work with older or newer versions than indicated. - -| Library Version | Deno Version | -|-----------------|--------------| -| main | 1.30.0 | -| 1.1.0 | 1.24.0 | -| 1.0.0 | 1.15.3 | -| 0.0.2 | ??? | -| 0.0.1 | ??? | +Versions adhere to the following versioning system of `x.y.z` where: +- `x` means a breaking change (eg. removal of a function, breaking upgrade of an upstream dependency etc.). +- `y` means an addition or non-breaking update. +- `z` means a typos, bug-fix etc. diff --git a/docs/communication.md b/docs/communication.md new file mode 100644 index 00000000..dba7f571 --- /dev/null +++ b/docs/communication.md @@ -0,0 +1,3 @@ +# Communication + +TODO diff --git a/docs/core.md b/docs/core.md new file mode 100644 index 00000000..9fbc65bf --- /dev/null +++ b/docs/core.md @@ -0,0 +1,3 @@ +# Core + +TODO diff --git a/docs/discord.md b/docs/discord.md new file mode 100644 index 00000000..eec383ef --- /dev/null +++ b/docs/discord.md @@ -0,0 +1,3 @@ +# Discord + +TODO diff --git a/docs/error.md b/docs/error.md new file mode 100644 index 00000000..e7341352 --- /dev/null +++ b/docs/error.md @@ -0,0 +1,3 @@ +# Error + +TODO diff --git a/docs/filesystem.md b/docs/filesystem.md new file mode 100644 index 00000000..012cd64c --- /dev/null +++ b/docs/filesystem.md @@ -0,0 +1,3 @@ +# Filesystem + +TODO diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000..031c30d9 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,33 @@ +# Getting Started + +Chomp is structured in such a way that you can import just what you need for your app. +A good start would be to import the most common things you might use: +```ts +import * from "https://deno.land/x/chomp/mod.ts"; +``` + +This includes (list might not always be up-to-date): +- `Cache` +- `Configure` +- `Logger` +- `raise` +- `File` +- `Folder` +- `CheckSource` + +You can then import any of the "extras" as you need: + +- Discord Bot (Discordeno Wrapper): +```ts +import * from "https://deno.land/x/chomp/discord/mod.ts"; +``` +- Weberver: +```ts +import * from "https://deno.land/x/chomp/webserver/mod.ts"; +``` +- Websocket Server: +```ts +import * from "https://deno.land/x/chomp/websocket/mod.ts"; +``` + +But there's plenty more you can use. diff --git a/docs/logging.md b/docs/logging.md new file mode 100644 index 00000000..6821e452 --- /dev/null +++ b/docs/logging.md @@ -0,0 +1,3 @@ +# Logging + +TODO diff --git a/docs/queue.md b/docs/queue.md new file mode 100644 index 00000000..4babe179 --- /dev/null +++ b/docs/queue.md @@ -0,0 +1,3 @@ +# Queue + +TODO diff --git a/docs/security.md b/docs/security.md new file mode 100644 index 00000000..ae3bdb8a --- /dev/null +++ b/docs/security.md @@ -0,0 +1,3 @@ +# Security + +TODO diff --git a/docs/utility.md b/docs/utility.md new file mode 100644 index 00000000..223fb761 --- /dev/null +++ b/docs/utility.md @@ -0,0 +1,3 @@ +# Utility + +TODO diff --git a/docs/webserver.md b/docs/webserver.md new file mode 100644 index 00000000..52e836c6 --- /dev/null +++ b/docs/webserver.md @@ -0,0 +1,3 @@ +# Webserver + +TODO diff --git a/docs/websocket.md b/docs/websocket.md new file mode 100644 index 00000000..6690c76c --- /dev/null +++ b/docs/websocket.md @@ -0,0 +1,3 @@ +# Websocket + +TODO From 47a643ea87fecb4232437ce0c87d4d48a7dbff0a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 24 Jan 2024 15:33:37 +0100 Subject: [PATCH 134/379] Add InteractionBuilder --- discord/mod.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/discord/mod.ts b/discord/mod.ts index a23365a6..e192a585 100644 --- a/discord/mod.ts +++ b/discord/mod.ts @@ -8,6 +8,7 @@ export { EventDispatcher } from "./event/dispatcher.ts"; export type { Event } from "./event/event.ts"; // Export InteractionDispatcher +export { InteractionBuilder } from "./interaction/builder.ts"; export { InteractionDispatcher } from "./interaction/dispatcher.ts"; export type { InteractionConfig } from "./interaction/dispatcher.ts"; export { Interaction } from "./interaction/interaction.ts"; From 1fd5eeec7ff182b828d18e0a7210c13f8241a125 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 24 Jan 2024 15:35:08 +0100 Subject: [PATCH 135/379] Change exports a wee bit --- discord/mod.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discord/mod.ts b/discord/mod.ts index e192a585..e7afc197 100644 --- a/discord/mod.ts +++ b/discord/mod.ts @@ -8,8 +8,8 @@ export { EventDispatcher } from "./event/dispatcher.ts"; export type { Event } from "./event/event.ts"; // Export InteractionDispatcher -export { InteractionBuilder } from "./interaction/builder.ts"; -export { InteractionDispatcher } from "./interaction/dispatcher.ts"; +export * from "./interaction/builder.ts"; +export * from "./interaction/dispatcher.ts"; export type { InteractionConfig } from "./interaction/dispatcher.ts"; export { Interaction } from "./interaction/interaction.ts"; From f19c767e82f865d8e5b771da5b0c426645e07ea3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 24 Jan 2024 23:48:58 +0100 Subject: [PATCH 136/379] Move getting started to main README.md --- README.md | 31 ++++++++++++++++++++++++++++++- docs/getting-started.md | 33 --------------------------------- 2 files changed, 30 insertions(+), 34 deletions(-) delete mode 100644 docs/getting-started.md diff --git a/README.md b/README.md index dfe5808b..ca74e496 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,36 @@ Should work just fine but comes with no warranties whatsoever. ## Usage -You can read the [Getting Started](docs/getting-started.md) to see how to use Chomp. +Chomp is structured in such a way that you can import just what you need for your app. +A good start would be to import the most common things you might use: +```ts +import * from "https://deno.land/x/chomp/mod.ts"; +``` + +This includes (list might not always be up-to-date): +- `Cache` +- `Configure` +- `Logger` +- `raise` +- `File` +- `Folder` +- `CheckSource` + +You can then import any of the "extras" as you need: + +- Discord Bot (Discordeno Wrapper): +```ts +import * from "https://deno.land/x/chomp/discord/mod.ts"; +``` +- Weberver: +```ts +import * from "https://deno.land/x/chomp/webserver/mod.ts"; +``` +- Websocket Server: +```ts +import * from "https://deno.land/x/chomp/websocket/mod.ts"; +``` + Additionally, you can visit the [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what Chomp is capable off! ## Versioning diff --git a/docs/getting-started.md b/docs/getting-started.md deleted file mode 100644 index 031c30d9..00000000 --- a/docs/getting-started.md +++ /dev/null @@ -1,33 +0,0 @@ -# Getting Started - -Chomp is structured in such a way that you can import just what you need for your app. -A good start would be to import the most common things you might use: -```ts -import * from "https://deno.land/x/chomp/mod.ts"; -``` - -This includes (list might not always be up-to-date): -- `Cache` -- `Configure` -- `Logger` -- `raise` -- `File` -- `Folder` -- `CheckSource` - -You can then import any of the "extras" as you need: - -- Discord Bot (Discordeno Wrapper): -```ts -import * from "https://deno.land/x/chomp/discord/mod.ts"; -``` -- Weberver: -```ts -import * from "https://deno.land/x/chomp/webserver/mod.ts"; -``` -- Websocket Server: -```ts -import * from "https://deno.land/x/chomp/websocket/mod.ts"; -``` - -But there's plenty more you can use. From 2fa5007bae4266d04301964b9054aabb6be43975 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 24 Jan 2024 23:57:10 +0100 Subject: [PATCH 137/379] Start documenting CouchDB --- docs/communication.md | 52 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/docs/communication.md b/docs/communication.md index dba7f571..597d8076 100644 --- a/docs/communication.md +++ b/docs/communication.md @@ -1,3 +1,53 @@ # Communication -TODO +Classes that abstract communication with other services. + +## CouchDB + +Facilitates communication with [CouchDB](https://couchdb.apache.org/). + +```ts +import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; +``` + +### Connecting + +First, we must pass all the information to the class so it can properly connect to CouchDB. + +```ts +// Option 1 (preferred) +const db1 = new CouchDB('http://localhost:5984', 'my_database', { username: 'couchuser', password: 'lamepassword'}); + +// Option 2 +const db2 = new CouchDB('http://localhost:5984', 'my_database'); +db2.username = 'couchuser'; +db2.password = 'lamepassword'; +``` + +### Getting a document + +### Inserting a document + +### Updating a document + +### Upserting a document + +### Deleting a document + +### Making a raw query + +## Druid + +## GraphQL + +## InfluxDB + +## Loki + +## NTFY + +## NUT + +## RCON + +## Redis From ccf016bb594e282714ab77d12154f1cc71a8330b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 24 Jan 2024 23:58:24 +0100 Subject: [PATCH 138/379] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca74e496..2cec9ff6 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ import * from "https://deno.land/x/chomp/webserver/mod.ts"; import * from "https://deno.land/x/chomp/websocket/mod.ts"; ``` -Additionally, you can visit the [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what Chomp is capable off! +Additionally, you can visit the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what Chomp is capable off! ## Versioning From 8c71f7d36c3e93b71cecf09174d96bff88193953 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 00:09:54 +0100 Subject: [PATCH 139/379] Restructure documentation a bit. --- docs/communication.md | 53 -------------------- docs/communication/README.md | 3 ++ docs/communication/couchdb.md | 36 +++++++++++++ docs/communication/druid.md | 1 + docs/communication/graphql.md | 7 +++ docs/communication/influxdb.md | 1 + docs/communication/loki.md | 1 + docs/communication/ntfy.md | 1 + docs/communication/nut.md | 1 + docs/communication/rcon.md | 1 + docs/communication/redis.md | 1 + docs/{core.md => core/README.md} | 2 - docs/{discord.md => discord/README.md} | 2 - docs/{error.md => error/README.md} | 2 - docs/{filesystem.md => filesystem/README.md} | 2 - docs/logging.md | 3 -- docs/logging/README.md | 0 docs/{queue.md => queue/README.md} | 2 - docs/{security.md => security/README.md} | 2 - docs/{utility.md => utility/README.md} | 2 - docs/webserver.md | 3 -- docs/webserver/README.md | 4 ++ docs/{websocket.md => websocket/README.md} | 2 - 23 files changed, 57 insertions(+), 75 deletions(-) delete mode 100644 docs/communication.md create mode 100644 docs/communication/README.md create mode 100644 docs/communication/couchdb.md create mode 100644 docs/communication/druid.md create mode 100644 docs/communication/graphql.md create mode 100644 docs/communication/influxdb.md create mode 100644 docs/communication/loki.md create mode 100644 docs/communication/ntfy.md create mode 100644 docs/communication/nut.md create mode 100644 docs/communication/rcon.md create mode 100644 docs/communication/redis.md rename docs/{core.md => core/README.md} (53%) rename docs/{discord.md => discord/README.md} (62%) rename docs/{error.md => error/README.md} (57%) rename docs/{filesystem.md => filesystem/README.md} (68%) delete mode 100644 docs/logging.md create mode 100644 docs/logging/README.md rename docs/{queue.md => queue/README.md} (57%) rename docs/{security.md => security/README.md} (64%) rename docs/{utility.md => utility/README.md} (62%) delete mode 100644 docs/webserver.md create mode 100644 docs/webserver/README.md rename docs/{websocket.md => websocket/README.md} (66%) diff --git a/docs/communication.md b/docs/communication.md deleted file mode 100644 index 597d8076..00000000 --- a/docs/communication.md +++ /dev/null @@ -1,53 +0,0 @@ -# Communication - -Classes that abstract communication with other services. - -## CouchDB - -Facilitates communication with [CouchDB](https://couchdb.apache.org/). - -```ts -import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; -``` - -### Connecting - -First, we must pass all the information to the class so it can properly connect to CouchDB. - -```ts -// Option 1 (preferred) -const db1 = new CouchDB('http://localhost:5984', 'my_database', { username: 'couchuser', password: 'lamepassword'}); - -// Option 2 -const db2 = new CouchDB('http://localhost:5984', 'my_database'); -db2.username = 'couchuser'; -db2.password = 'lamepassword'; -``` - -### Getting a document - -### Inserting a document - -### Updating a document - -### Upserting a document - -### Deleting a document - -### Making a raw query - -## Druid - -## GraphQL - -## InfluxDB - -## Loki - -## NTFY - -## NUT - -## RCON - -## Redis diff --git a/docs/communication/README.md b/docs/communication/README.md new file mode 100644 index 00000000..6ee19085 --- /dev/null +++ b/docs/communication/README.md @@ -0,0 +1,3 @@ +# Communication + +Classes that abstract communication with other services. diff --git a/docs/communication/couchdb.md b/docs/communication/couchdb.md new file mode 100644 index 00000000..af4cf69b --- /dev/null +++ b/docs/communication/couchdb.md @@ -0,0 +1,36 @@ +# CouchDB + +Facilitates communication with [CouchDB](https://couchdb.apache.org/). + +### Getting Started + +First import the module as follows: +```ts +import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; +``` + +Next, we must create an instance of the class that we can use to talk to CouchDB. + +```ts +// Option 1 (preferred) +const db = new CouchDB('http://localhost:5984', 'my_database', { username: 'couchuser', password: 'lamepassword'}); +``` + +```ts +// Option 2 +const db = new CouchDB('http://localhost:5984', 'my_database'); +db.username = 'couchuser'; +db.password = 'lamepassword'; +``` + +## Getting a document + +## Inserting a document + +## Updating a document + +## Upserting a document + +## Deleting a document + +## Making a raw query diff --git a/docs/communication/druid.md b/docs/communication/druid.md new file mode 100644 index 00000000..d9617382 --- /dev/null +++ b/docs/communication/druid.md @@ -0,0 +1 @@ +# Druid diff --git a/docs/communication/graphql.md b/docs/communication/graphql.md new file mode 100644 index 00000000..4c81b379 --- /dev/null +++ b/docs/communication/graphql.md @@ -0,0 +1,7 @@ +# GraphQL + +Facilitates querying and mutating GraphQL APIs. + +## Getting Started + +TODO diff --git a/docs/communication/influxdb.md b/docs/communication/influxdb.md new file mode 100644 index 00000000..4abe4564 --- /dev/null +++ b/docs/communication/influxdb.md @@ -0,0 +1 @@ +# InfluxDB diff --git a/docs/communication/loki.md b/docs/communication/loki.md new file mode 100644 index 00000000..702c5b7a --- /dev/null +++ b/docs/communication/loki.md @@ -0,0 +1 @@ +# Loki diff --git a/docs/communication/ntfy.md b/docs/communication/ntfy.md new file mode 100644 index 00000000..4a856ebf --- /dev/null +++ b/docs/communication/ntfy.md @@ -0,0 +1 @@ +# Ntfy diff --git a/docs/communication/nut.md b/docs/communication/nut.md new file mode 100644 index 00000000..6d2eb3ca --- /dev/null +++ b/docs/communication/nut.md @@ -0,0 +1 @@ +# NUT diff --git a/docs/communication/rcon.md b/docs/communication/rcon.md new file mode 100644 index 00000000..b9a977d2 --- /dev/null +++ b/docs/communication/rcon.md @@ -0,0 +1 @@ +# RCON diff --git a/docs/communication/redis.md b/docs/communication/redis.md new file mode 100644 index 00000000..51a87de7 --- /dev/null +++ b/docs/communication/redis.md @@ -0,0 +1 @@ +# Redis diff --git a/docs/core.md b/docs/core/README.md similarity index 53% rename from docs/core.md rename to docs/core/README.md index 9fbc65bf..3b616f93 100644 --- a/docs/core.md +++ b/docs/core/README.md @@ -1,3 +1 @@ # Core - -TODO diff --git a/docs/discord.md b/docs/discord/README.md similarity index 62% rename from docs/discord.md rename to docs/discord/README.md index eec383ef..8b32d7a1 100644 --- a/docs/discord.md +++ b/docs/discord/README.md @@ -1,3 +1 @@ # Discord - -TODO diff --git a/docs/error.md b/docs/error/README.md similarity index 57% rename from docs/error.md rename to docs/error/README.md index e7341352..8a547396 100644 --- a/docs/error.md +++ b/docs/error/README.md @@ -1,3 +1 @@ # Error - -TODO diff --git a/docs/filesystem.md b/docs/filesystem/README.md similarity index 68% rename from docs/filesystem.md rename to docs/filesystem/README.md index 012cd64c..6d41ab86 100644 --- a/docs/filesystem.md +++ b/docs/filesystem/README.md @@ -1,3 +1 @@ # Filesystem - -TODO diff --git a/docs/logging.md b/docs/logging.md deleted file mode 100644 index 6821e452..00000000 --- a/docs/logging.md +++ /dev/null @@ -1,3 +0,0 @@ -# Logging - -TODO diff --git a/docs/logging/README.md b/docs/logging/README.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/queue.md b/docs/queue/README.md similarity index 57% rename from docs/queue.md rename to docs/queue/README.md index 4babe179..d095a2b0 100644 --- a/docs/queue.md +++ b/docs/queue/README.md @@ -1,3 +1 @@ # Queue - -TODO diff --git a/docs/security.md b/docs/security/README.md similarity index 64% rename from docs/security.md rename to docs/security/README.md index ae3bdb8a..8dbb2f9b 100644 --- a/docs/security.md +++ b/docs/security/README.md @@ -1,3 +1 @@ # Security - -TODO diff --git a/docs/utility.md b/docs/utility/README.md similarity index 62% rename from docs/utility.md rename to docs/utility/README.md index 223fb761..0b58bca8 100644 --- a/docs/utility.md +++ b/docs/utility/README.md @@ -1,3 +1 @@ # Utility - -TODO diff --git a/docs/webserver.md b/docs/webserver.md deleted file mode 100644 index 52e836c6..00000000 --- a/docs/webserver.md +++ /dev/null @@ -1,3 +0,0 @@ -# Webserver - -TODO diff --git a/docs/webserver/README.md b/docs/webserver/README.md new file mode 100644 index 00000000..a1ca346b --- /dev/null +++ b/docs/webserver/README.md @@ -0,0 +1,4 @@ +# Webserver + +Collection that facilitates easily setting up a webserver. +Adheres to a [CakePHP](https://cakephp.org/)-style Convention-over-Configuration. diff --git a/docs/websocket.md b/docs/websocket/README.md similarity index 66% rename from docs/websocket.md rename to docs/websocket/README.md index 6690c76c..a82b3e3c 100644 --- a/docs/websocket.md +++ b/docs/websocket/README.md @@ -1,3 +1 @@ # Websocket - -TODO From 8605e81f4cfaa24f5aad00c5ce54d569ec45f7da Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 00:12:09 +0100 Subject: [PATCH 140/379] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2cec9ff6..a49677aa 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ You can then import any of the "extras" as you need: ```ts import * from "https://deno.land/x/chomp/discord/mod.ts"; ``` -- Weberver: +- Webserver: ```ts import * from "https://deno.land/x/chomp/webserver/mod.ts"; ``` From cf6b95278eb678fa3e759bb06e9a81a31819dd4a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 00:16:48 +0100 Subject: [PATCH 141/379] Add links to pages --- README.md | 22 +++++++++++----------- docs/core/cache.md | 1 + docs/core/configure.md | 1 + docs/error/raise.md | 0 docs/filesystem/file.md | 1 + docs/filesystem/folder.md | 1 + docs/logging/logger.md | 1 + docs/utility/check-source.md | 1 + 8 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 docs/core/cache.md create mode 100644 docs/core/configure.md create mode 100644 docs/error/raise.md create mode 100644 docs/filesystem/file.md create mode 100644 docs/filesystem/folder.md create mode 100644 docs/logging/logger.md create mode 100644 docs/utility/check-source.md diff --git a/README.md b/README.md index a49677aa..48947b95 100644 --- a/README.md +++ b/README.md @@ -11,30 +11,30 @@ import * from "https://deno.land/x/chomp/mod.ts"; ``` This includes (list might not always be up-to-date): -- `Cache` -- `Configure` -- `Logger` -- `raise` -- `File` -- `Folder` -- `CheckSource` +- [Cache](docs/core/cache.md) +- [Configure](docs/core/configure.md) +- [Logger](docs/logging/logger.md) +- [raise](docs/error/raise.md) +- [File](docs/filesystem/file.md) +- [Folder](docs/filesystem/folder.md) +- [CheckSource](docs/utility/check-source.md) You can then import any of the "extras" as you need: -- Discord Bot (Discordeno Wrapper): +- [Discord Bot](docs/discord/README.md) (Discordeno Wrapper): ```ts import * from "https://deno.land/x/chomp/discord/mod.ts"; ``` -- Webserver: +- [Webserver](docs/webserver/README.md): ```ts import * from "https://deno.land/x/chomp/webserver/mod.ts"; ``` -- Websocket Server: +- [Websocket Server](docs/websocket/README.md): ```ts import * from "https://deno.land/x/chomp/websocket/mod.ts"; ``` -Additionally, you can visit the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what Chomp is capable off! +Additionally, you can visit the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what more Chomp is capable off! ## Versioning diff --git a/docs/core/cache.md b/docs/core/cache.md new file mode 100644 index 00000000..d423f065 --- /dev/null +++ b/docs/core/cache.md @@ -0,0 +1 @@ +# Cache diff --git a/docs/core/configure.md b/docs/core/configure.md new file mode 100644 index 00000000..c6bc78e9 --- /dev/null +++ b/docs/core/configure.md @@ -0,0 +1 @@ +# Configure diff --git a/docs/error/raise.md b/docs/error/raise.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/filesystem/file.md b/docs/filesystem/file.md new file mode 100644 index 00000000..7ac8882e --- /dev/null +++ b/docs/filesystem/file.md @@ -0,0 +1 @@ +# File diff --git a/docs/filesystem/folder.md b/docs/filesystem/folder.md new file mode 100644 index 00000000..658b202c --- /dev/null +++ b/docs/filesystem/folder.md @@ -0,0 +1 @@ +# Folder diff --git a/docs/logging/logger.md b/docs/logging/logger.md new file mode 100644 index 00000000..441dd59e --- /dev/null +++ b/docs/logging/logger.md @@ -0,0 +1 @@ +# Logger diff --git a/docs/utility/check-source.md b/docs/utility/check-source.md new file mode 100644 index 00000000..af14f17a --- /dev/null +++ b/docs/utility/check-source.md @@ -0,0 +1 @@ +# CheckSource From b53082c31b17ea845e9869ac5d265535e332a11e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 00:16:55 +0100 Subject: [PATCH 142/379] Change wording a bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48947b95..f070a53c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ import * from "https://deno.land/x/chomp/webserver/mod.ts"; import * from "https://deno.land/x/chomp/websocket/mod.ts"; ``` -Additionally, you can visit the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what more Chomp is capable off! +Additionally, you can explore the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what more Chomp is capable off! ## Versioning From 2bbe2de0ffa7b9ecfde860386b76014327c307aa Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 00:17:45 +0100 Subject: [PATCH 143/379] Missing header --- docs/error/raise.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/error/raise.md b/docs/error/raise.md index e69de29b..64f43ee3 100644 --- a/docs/error/raise.md +++ b/docs/error/raise.md @@ -0,0 +1 @@ +# raise From 7122c535796564c5cc70a5ac5612030f4ea813db Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 08:46:28 +0100 Subject: [PATCH 144/379] Add optimistic caching, use a Map instead of an object and add a consume method to Cache --- core/cache.ts | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index 2114f83d..f2135f87 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -1,14 +1,12 @@ import { T as TimeString } from "../utility/time-string.ts"; interface CacheItem { - [key: string]: { - data: unknown; - expires: Date|null; - } + data: unknown; + expires: Date|null; } export class Cache { - private static _items: CacheItem = {}; + private static _items: Map = new Map(); /** * Add an item to the cache. @@ -21,26 +19,27 @@ export class Cache { let expiresAt = null; if(expiry) expiresAt = new Date(new Date().getTime() + TimeString`${expiry}`) - Cache._items[key] = { + Cache._items.set(key, { data: value, expires: expiresAt, - }; + }); } /** * Get an item from the cache * * @param key + * @param optimistic Whether to serve expired items from the cache */ - public static get(key: string): unknown|null { + public static get(key: string, optimistic = false): unknown|null { // Return null if the item doesn't exist if(!Cache.exists(key)) return null; // Return null if the item expired - if(Cache.expired(key)) return null; + if(Cache.expired(key) && !optimistic) return null; // Return the item's data - return Cache._items[key].data; + return Cache._items.get(key)?.data; } /** @@ -50,7 +49,7 @@ export class Cache { * @param key */ public static exists(key: string): boolean { - return key in Cache._items; + return Cache._items.has(key); } /** @@ -63,8 +62,26 @@ export class Cache { if(!Cache.exists(key)) return true; // Check if the expiry date is before our current date - if(!Cache._items[key].expires) return false; - return Cache._items[key].expires! < new Date(); + if(!Cache._items.get(key)?.expires) return false; + return Cache._items.get(key)?.expires! < new Date(); + } + + /** + * Consume an item from the cache. + * Differs from "Cache.get()" in that it removes the item afterwards. + * + * @param key + * @param optimistic Whether to serve expired items from the cache + */ + public static consume(key: string, optimistic = false): unknown|null { + // Copy item from cache + const data = Cache.get(key, optimistic); + + // Remove item from cache + Cache.remove(key); + + // Return the item + return data; } /** @@ -77,6 +94,6 @@ export class Cache { if(!Cache.exists(key)) return; // Delete our item - delete Cache._items[key]; + Cache._items.delete(key); } } From 19d1226260a5aa31598754ec5579ee58ea52fc33 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 08:58:33 +0100 Subject: [PATCH 145/379] Add Cache.dump() method --- core/cache.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/cache.ts b/core/cache.ts index f2135f87..55758215 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -96,4 +96,12 @@ export class Cache { // Delete our item Cache._items.delete(key); } + + /** + * Dumps the raw cache contents. + * Should only be used for debugging purposes. + */ + public static dump(): Map { + return Cache._items; + } } From b46665e4679f4ef6e547db45e98403d486da0e32 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 09:17:36 +0100 Subject: [PATCH 146/379] Clean up cache every hour --- core/cache.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/core/cache.ts b/core/cache.ts index 55758215..f7b3ae8f 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -1,4 +1,6 @@ import { T as TimeString } from "../utility/time-string.ts"; +import { Logger } from "../logging/logger.ts"; +import { Cron } from "../utility/cron.ts"; interface CacheItem { data: unknown; @@ -104,4 +106,44 @@ export class Cache { public static dump(): Map { return Cache._items; } + + /** + * Scan the cache and clean up expired items while keeping optimistic caching in tact. + */ + public static sweep(): void { + // Set the start time of this sweep + // Set an optimistic boundary + // TODO: Allow configuring of optimistic boundary + const now = new Date(); + const start = new Date(now.getTime() + TimeString`-1 hour -1 second`); + const boundary = new Date(now.getTime() + TimeString`-1 hour -1 minute`); + + // Loop over each item in the cache + for(const [key, value] of Cache._items) { + // Keep items that do not expire + if(!value.expires) { + Logger.debug(`Keeping cache item "${key}": Does not expire`); + continue; + } + + // Keep items that have not yet expired + if(value.expires >= start) { + Logger.debug(`Keeping cache item "${key}": Has not expired`); + continue; + } + + // Keep items that may be served optimistically + if(value.expires >= boundary) { + Logger.debug(`Keeping cache item "${key}": Keep for optimistic caching`); + continue; + } + + // Clean up items that have expired + Logger.debug(`Removing expired cache item "${key}"`); + Cache._items.delete(key); + } + } } + +// Sweep cache every hour +Cron('1 0 * * * *', () => Cache.sweep()); From 0d15ddc1cf75faaac3987268041996edbbe87c00 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 09:23:12 +0100 Subject: [PATCH 147/379] No need to check if an item existed --- core/cache.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index f7b3ae8f..ff572439 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -92,9 +92,6 @@ export class Cache { * @param key */ public static remove(key: string): void { - // Return if the item doesn't exist - if(!Cache.exists(key)) return; - // Delete our item Cache._items.delete(key); } From e50a927afff3d58c0df84a66d61e3f0cd9a43519 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 09:23:28 +0100 Subject: [PATCH 148/379] Over-documentation --- core/cache.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/cache.ts b/core/cache.ts index ff572439..e26922ff 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -92,7 +92,6 @@ export class Cache { * @param key */ public static remove(key: string): void { - // Delete our item Cache._items.delete(key); } From e58302dd65bc7e67c7b94b9eee0dab6aeb1bc54e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 09:37:12 +0100 Subject: [PATCH 149/379] Document Cache --- docs/core/cache.md | 86 +++++++++++++++++++++++++++++++++++++ docs/utility/time-string.md | 1 + 2 files changed, 87 insertions(+) create mode 100644 docs/utility/time-string.md diff --git a/docs/core/cache.md b/docs/core/cache.md index d423f065..94502412 100644 --- a/docs/core/cache.md +++ b/docs/core/cache.md @@ -1 +1,87 @@ # Cache + +Facilitates keeping items in memory for a set (or indefinite) period of time. + +## Adding an item to the Cache + +Adding an item to the cache is as simple as calling `Cache.set()`. +By default, items will expire in `1 minute`, however, this can be changed if desired. +```ts +Cache.set('I expire in 1 minute', 'foo'); +Cache.set('I expire in 10 minutes', 'bar', '+10 minutes'); +Cache.set('I never expire', 'baz', null); +``` + +**NOTE**: Expiry times use [TimeString](../utility/time-string.md) formats. + +## Getting an item from the Cache + +You can get items from the cache by calling `Cache.get()`. +```ts +Cache.get('cache item name'); // Honours expiry +Cache.get('cache item name', true); // Optimistically serve expired cache items +``` + +## Checking if an item exists in Cache + +You can check if an item exists in the cache by calling `Cache.exists()`. +However, this does not check whether an item has expired or not so it may exist only if obtained optimistically. +```ts +Cache.exists('cache item name'); +``` + +## Checking if an item has expired + +You can check if an item exists *and* has not yet expired by calling `Cache.expired()`. +Items that have expired *may* still exist but only be able to be obtained optimistically. +```ts +Cache.expired('cache item name'); +``` + +## Remove an item from the Cache + +If you want to remove an item from the cache, you can simply call `Cache.remove()`. +```ts +Cache.remove('cache item name'); +``` + +## Showing all items in Cache + +You can obtain the raw cache contents using the `Cache.dump()` method. +```ts +console.log(Cache.dump()); +``` + +```ts +Map(1) { + "cache item name" => { data: "cache item value", expires: null } +} +``` + +**NOTE**: This should only be done for debugging purposes! + +## Cleaning up expired items + +By default, the cache will be cleaned up every hour. +Items may linger in the cache for up-to an additional hour to enable for more predictable optimistic caching. + +If you want to clean up expired cache items manually, you can do so by running `Cache.sweep()`. +```ts +console.log(Cache.dump()); +Cache.sweep(); +console.log(Cache.dump()); +``` + +```ts +Map(4) { + "entry #1 (expired)" => { data: 1234, expires: 2024-01-25T07:09:04.252Z }, + "entry #2 (expired, optimistic)" => { data: 1234, expires: 2024-01-25T07:20:04.253Z }, + "entry #3 (valid)" => { data: 1234, expires: 2024-01-25T09:20:04.253Z }, + "entry #4 (valid, indefinite)" => { data: 1234, expires: null } +} +Map(3) { + "entry #2 (expired, optimistic)" => { data: 1234, expires: 2024-01-25T07:20:04.253Z }, + "entry #3 (valid)" => { data: 1234, expires: 2024-01-25T09:20:04.253Z }, + "entry #4 (valid, indefinite)" => { data: 1234, expires: null } +} +``` diff --git a/docs/utility/time-string.md b/docs/utility/time-string.md new file mode 100644 index 00000000..24063fe8 --- /dev/null +++ b/docs/utility/time-string.md @@ -0,0 +1 @@ +# TimeString From ca18b4c7cb313e41d80d4b96bdce2c4a1737122c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 09:40:43 +0100 Subject: [PATCH 150/379] Remove "raise" from default package --- mod.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/mod.ts b/mod.ts index fbda1f53..64f5b568 100644 --- a/mod.ts +++ b/mod.ts @@ -5,7 +5,6 @@ export { Cache } from "./core/cache.ts"; export { Configure } from "./core/configure.ts"; export { Logger } from "./logging/logger.ts"; -export { raise } from "./error/raise.ts"; export { File } from "./filesystem/file.ts"; export { Folder } from "./filesystem/folder.ts"; export { CheckSource } from "./utility/check-source.ts"; From 5f336efaf45665a540eeeb931d147c51cad3b580 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 09:40:56 +0100 Subject: [PATCH 151/379] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index f070a53c..d6a523f0 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@ This includes (list might not always be up-to-date): - [Cache](docs/core/cache.md) - [Configure](docs/core/configure.md) - [Logger](docs/logging/logger.md) -- [raise](docs/error/raise.md) - [File](docs/filesystem/file.md) - [Folder](docs/filesystem/folder.md) - [CheckSource](docs/utility/check-source.md) From fe14476c42e24ab18d132d7c3db06d0eba688995 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 09:42:42 +0100 Subject: [PATCH 152/379] Update comment --- mod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod.ts b/mod.ts index 64f5b568..9c92e2ea 100644 --- a/mod.ts +++ b/mod.ts @@ -1,6 +1,6 @@ /** * These are just the exports you'll most commonly use. - * You can view the "README.md" to see what else there is! + * You can view the "docs"-directory to see what else there is! */ export { Cache } from "./core/cache.ts"; export { Configure } from "./core/configure.ts"; From 058e2931634f0ca4693f735da4e36568abe77749 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 17:17:33 +0100 Subject: [PATCH 153/379] Comments and allow creation of directories --- filesystem/folder.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/filesystem/folder.ts b/filesystem/folder.ts index c8698d01..541030b2 100644 --- a/filesystem/folder.ts +++ b/filesystem/folder.ts @@ -1,9 +1,14 @@ +import { Logger } from "../logging/logger.ts"; + export class Folder { public constructor( private readonly path: string ) { } - + + /** + * Check whether the folder exists at the path. + */ public async exists(): Promise { try { const target = await Deno.stat(this.path); @@ -13,4 +18,19 @@ export class Folder { throw e; } } + + /** + * Create the directory if it does not exist yet. + * + * @param options Options with which to create the directory + */ + public async create(options?: Deno.MkdirOptions): Promise { + try { + if(await this.exists()) throw new Error('The specified folder already exists!'); + } catch(e) { + Logger.warning(e.message); + } + + await Deno.mkdir(this.path, options); + } } From 9ae713b2d328b9a851e1c5847afab7bd246ce4b0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 17:23:33 +0100 Subject: [PATCH 154/379] Fix minor bug --- logging/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging/logger.ts b/logging/logger.ts index bca15407..fb082118 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -95,7 +95,7 @@ export class Logger { * * @returns {string} The formatted time */ - private static time(): string { + protected static time(): string { return new Time().format(Configure.get('logger.timeformat', 'yyyy/MM/dd HH:mm:ss')); } } From c55f7d7545d23c6bff44ac01730cd7d0a23197b2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 17:23:43 +0100 Subject: [PATCH 155/379] Set debug key by default --- core/configure.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/configure.ts b/core/configure.ts index 0e6d9efd..147b517f 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -2,6 +2,7 @@ import { Logger } from "../logging/logger.ts"; export class Configure { private static config = new Map([ + ['debug', false], ['error_log', `${Deno.cwd()}/logs/error.log`] ]); private static hasLoaded = false; From 12b18dcff53bc53df55a55547dfbd84fb4d38156 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 17:46:17 +0100 Subject: [PATCH 156/379] Allow resetting Configure to default state --- core/configure.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/core/configure.ts b/core/configure.ts index 147b517f..a573c77d 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,10 +1,12 @@ import { Logger } from "../logging/logger.ts"; +const defaults = [ + ['debug', false], + ['error_log', `${Deno.cwd()}/logs/error.log`] +]; + export class Configure { - private static config = new Map([ - ['debug', false], - ['error_log', `${Deno.cwd()}/logs/error.log`] - ]); + private static config = new Map(defaults); private static hasLoaded = false; /** @@ -114,11 +116,20 @@ export class Configure { } /** - * Clear all items in the configure (including defaults) + * Clear all items in the configure (including defaults). + * If you want to keep the defaults, use "Configure.reset()" instead. * * @returns void */ public static clear(): void { Configure.config.clear(); } + + /** + * Resets the configure to the defaults. + * If you do not want to keep the defaults, use "Configure.clear()" instead. + */ + public static reset(): void { + Configure.config = new Map(defaults); + } } From d7b73c339305b1bd70160d744783be2766fe1450 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 17:50:19 +0100 Subject: [PATCH 157/379] Start documenting the Configure --- docs/core/configure.md | 94 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/docs/core/configure.md b/docs/core/configure.md index c6bc78e9..f7229cd3 100644 --- a/docs/core/configure.md +++ b/docs/core/configure.md @@ -1 +1,95 @@ # Configure + +Allows easily setting application configs using JSON rather than environment-variables. + +## Getting Started + +First, create a file `config.json` at your application's root. +By default `debug` and `error_log` are set to these values. +If you want to change them, this is the place where to do it! +```json +{ + "debug": false, + "error_log": "logs/error.logs" +} +``` + +Then import the module as part of Chomp's core and load the configure: +```ts +import * from "https://deno.land/x/chomp/mod.ts"; + +await Configure.load(); +``` + +Although, if you want to use a more minimal setup: +```ts +import { Configure } from "https://deno.land/x/chomp/mod.ts"; + +await Configure.load(); +``` + +## Getting an item from the Configure + +Getting an item from the Configure can be done by calling `Configure.get()`. +Doing this will return either the value set in the configure or `null`. +```ts +const myConst = Configure.get('app configure item'); +``` + +If you want to have a default return value, then you can specify it as follows: +```ts +const myConst = Configure.get('app configure item', 'default value'); +``` + +## Setting or updating an item in the Configure + +**NOTE**: Changes made here do not persist between restarts of your app. + +## Checking whether an item exists + +## Consume a Configure item + +## Delete a Configure item + +## Dump all Configure items + +**NOTE**: This should only be done for debugging purposes as it may leak sensitive information! + +## Clear or reset all Configure items + +Made a mistake or have another reason to start with a clean Configure? Then this can be done in two ways: `Configure.clear()` and `Configure.reset()`. + +`Configure.clear()` will *completely* empty the configure: +```ts +console.log(Configure.dump()); +Configure.clear(); +console.log(Configure.dump()); +``` + +```ts +Map(3) { + "debug" => false, + "error_log" => "/path/to/logs/error.log", + "app configuration key" => "app configuration value" +} +Map(0) {} +``` + +Whereas `Configure.clear()` will reset the configure to it's default state: +```ts +console.log(Configure.dump()); +Configure.reset(); +console.log(Configure.dump()); +``` + +```ts +Map(3) { + "debug" => false, + "error_log" => "/path/to/logs/error.log", + "app configuration key" => "app configuration value" +} +Map(2) { + "debug" => false, + "error_log" => "/path/to/logs/error.log" +} +``` From 69e37c2a1bf2b4fd564d1a53cda3980041afd118 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Jan 2024 17:51:09 +0100 Subject: [PATCH 158/379] Add linebreak --- docs/core/configure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/configure.md b/docs/core/configure.md index f7229cd3..93244b95 100644 --- a/docs/core/configure.md +++ b/docs/core/configure.md @@ -4,7 +4,7 @@ Allows easily setting application configs using JSON rather than environment-var ## Getting Started -First, create a file `config.json` at your application's root. +First, create a file `config.json` at your application's root. By default `debug` and `error_log` are set to these values. If you want to change them, this is the place where to do it! ```json From fb920a38b09789802bb8b64724d7fff753ca4baf Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 10:13:44 +0100 Subject: [PATCH 159/379] Remove Codecov and replace with regular Deno test --- .github/workflows/codecov.yml | 24 ------------------------ .github/workflows/test.yml | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 24 deletions(-) delete mode 100644 .github/workflows/codecov.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml deleted file mode 100644 index 1b1e6f92..00000000 --- a/.github/workflows/codecov.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Code Coverage -on: [push, pull_request] -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v3 - with: - submodules: true - - name: Set up Deno - uses: denoland/setup-deno@v1 - with: - deno-version: "1.30.0" - - name: Run tests - run: deno test --coverage=./coverage --allow-read --allow-env - - name: Generate lcov - run: deno coverage ./coverage --lcov --exclude="test\\.(ts|js)|wasm\\.js|testdata" > coverage.lcov - - name: Upload Code Coverage Report - uses: codecov/codecov-action@v3 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - with: - files: coverage.lcov diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..876bf353 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,16 @@ +name: Tests +on: [push, pull_request] +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v3 + with: + submodules: true + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: "1.30.0" + - name: Run tests + run: deno test --allow-read --allow-env From 676bd63a544f76e06bf27d6ee0aa4c55b4992dc7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 12:09:44 +0100 Subject: [PATCH 160/379] Add deno lint stage --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 876bf353..7183c703 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,5 +12,7 @@ jobs: uses: denoland/setup-deno@v1 with: deno-version: "1.30.0" + - name: Lint + run: deno lint - name: Run tests run: deno test --allow-read --allow-env From e9a37532eafa77ad5963d03e69dc97190391b455 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 12:13:19 +0100 Subject: [PATCH 161/379] Change when to run actions --- .github/workflows/test.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7183c703..4be8c613 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,9 @@ name: Tests -on: [push, pull_request] +on: + push: + branches: [main] + pull_request: + branches: [main] jobs: test: runs-on: ubuntu-latest From 7f61bdda334f5a63fa5ca214f9da8e9443bb752f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 12:40:56 +0100 Subject: [PATCH 162/379] Fix deprecation --- webserver/routing/router.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index d5390a91..5a24c62d 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -1,4 +1,5 @@ import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts"; +import { readAll } from "https://deno.land/std@0.213.0/io/read_all.ts"; import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../utility/inflector.ts"; import { Logger } from "../../logging/logger.ts"; @@ -195,7 +196,7 @@ export class Router { const reader = readerFromStreamReader(request.body.getReader()); // Read all bytes - const buf: Uint8Array = await Deno.readAll(reader); + const buf: Uint8Array = await readAll(reader); // Decode and return return new TextDecoder("utf-8").decode(buf); From c108b757cde22b0505647ef1c885da745ec10350 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 12:41:23 +0100 Subject: [PATCH 163/379] Use const instead of let --- websocket/websocket.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/websocket/websocket.ts b/websocket/websocket.ts index 98a3ce53..6453bc08 100644 --- a/websocket/websocket.ts +++ b/websocket/websocket.ts @@ -55,10 +55,11 @@ export class Websocket { if(!message) return; // Decode the message - let data = JSON.parse(message); + const data = JSON.parse(message); + // Get the Event let event = data.event; - let tokens = []; + const tokens = []; for(let token of event.split('_')) { token = token.toLowerCase(); token = token[0].toUpperCase() + token.slice(1); From 35fb9f3b6fa3baeb69faf1de19c98f4086553171 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 12:41:36 +0100 Subject: [PATCH 164/379] Do allow inferrable types --- deno.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 deno.json diff --git a/deno.json b/deno.json new file mode 100644 index 00000000..9822b7b4 --- /dev/null +++ b/deno.json @@ -0,0 +1,7 @@ +{ + "lint": { + "rules": { + "exclude": ["no-inferrable-types"] + } + } +} From 97d0c7a8c682e45d8604a58b98444c914870f7bf Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 12:41:48 +0100 Subject: [PATCH 165/379] Replace let with const --- webserver/controller/controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 8d0f978d..538aff24 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -107,7 +107,7 @@ export class Controller { */ public async render(): Promise { let body: string|Uint8Array = ''; - let canCompress = true; + const canCompress = true; switch(this.getResponse().getHeaderLine('Content-Type').toLowerCase()) { case 'application/json': body = JSON.stringify(this._vars['data']); From 62676dfee4a23a614d64adf9dac3a7d47b651ec8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 12:43:29 +0100 Subject: [PATCH 166/379] Remove async and fix some type juggling --- webserver/routing/router.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 5a24c62d..2d309c3c 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -84,8 +84,8 @@ export class Router { route.route, request.headers, await Router.getBody(request), - await Router.getParams(route.route, route.path), - await Router.getQuery(request.url), + Router.getParams(route.route, route.path), + Router.getQuery(request.url), Router.getAuth(request), clientIp ); @@ -158,14 +158,14 @@ export class Router { * * @param route * @param path - * @returns Promise<{ [key: string]: string }> + * @returns RequestParameters */ - public static async getParams(route: ChompRoute, path: string): Promise { + public static getParams(route: ChompRoute, path: string): RequestParameters { // Strip off query parameters - path = path.split("%3F"); - path = path[0]; + const pathSplit = path.split("%3F"); + path = pathSplit[0]; - const keys: any[] = []; + const keys: string[] = []; const r = pathToRegexp(route.getPath(), keys).exec(path) || []; return keys.reduce((acc, key, i) => ({ [key.name]: r[i + 1], ...acc }), {}); @@ -175,9 +175,9 @@ export class Router { * Get the query parameters for the given route * * @param path - * @returns Promise + * @returns QueryParameters */ - public static async getQuery(path: string): Promise { + public static getQuery(path: string): QueryParameters { const params = new URLSearchParams(path.split("?")[1]); return Object.fromEntries(params.entries()); } From 89cf56441f7cbf203b09c414a275a0eabcf60d6a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 13:35:04 +0100 Subject: [PATCH 167/379] Remove redundant check --- webserver/renderers/handlebars.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index 1a6f2df3..d6aa8341 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -20,7 +20,7 @@ export class Handlebars { // Compile our template // Cache it if need be const compiled = hbs.compile(template) ?? raise('Could not compile template'); - if(cache) if(cache) Handlebars._cache[path] = compiled; + if(cache) Handlebars._cache[path] = compiled; // Let the engine render return compiled(vars); From ee3bd5f1ad0c0fba4b2de21337cd0891592100fb Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 13:36:55 +0100 Subject: [PATCH 168/379] Do not use async and remove unused variable --- tests/common/configure.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common/configure.test.ts b/tests/common/configure.test.ts index 20549d4a..ed4fa036 100644 --- a/tests/common/configure.test.ts +++ b/tests/common/configure.test.ts @@ -1,7 +1,7 @@ import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; import { Configure } from "../../core/configure.ts"; -Deno.test("Configure Test", async (t) => { +Deno.test("Configure Test", () => { // Add a test variable and test against it Configure.set('test1', 'chomp'); assertEquals(Configure.check('test1'), true); From 8f8cc4bd81ba3faedfc1cba7b88cd2e835769f22 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 13:39:34 +0100 Subject: [PATCH 169/379] Remove any from Discord --- discord/discord.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discord/discord.ts b/discord/discord.ts index 4101c047..a46bde26 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -21,7 +21,7 @@ export interface DiscordInitOpts { export class Discord { protected static bot: Bot|BotWithCache|undefined; protected token = ''; - protected intents: any; + protected intents: number; protected botId = BigInt(0); /** @@ -37,7 +37,7 @@ export class Discord { Logger.error('No Discord bot token was provided!'); Deno.exit(1); } - if('intents' in opts) this.intents = opts.intents; + this.intents = 'intents' in opts ? opts.intents : 0; if('botId' in opts) this.botId = BigInt(opts.botId); const baseBot = createBot({ From 962f04e428b49973d672c557210a026066f8c756 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 13:41:39 +0100 Subject: [PATCH 170/379] Remove any --- discord/util/find-channel-by-name.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/discord/util/find-channel-by-name.ts b/discord/util/find-channel-by-name.ts index e86c45a0..857aa760 100644 --- a/discord/util/find-channel-by-name.ts +++ b/discord/util/find-channel-by-name.ts @@ -1,4 +1,4 @@ -import { Discord } from "../mod.ts"; +import { Discord, Channel } from "../mod.ts"; import { Logger } from "../../logging/logger.ts"; /** @@ -10,14 +10,14 @@ import { Logger } from "../../logging/logger.ts"; * @param guild * @param name */ -export async function findChannelByName(guild: BigInt, name: string): Promise { +export async function findChannelByName(guild: BigInt, name: string): Promise { const channels = await Discord.getBot().helpers.getChannels(guild); if(!channels) { Logger.error(`Could not obtain channels for guild! (this is a bug!)`); return null; } - const channel = channels.find((channel: any) => channel.name === name.toLowerCase()); + const channel = channels.find((channel: Channel) => channel.name === name.toLowerCase()); if(!channel) { Logger.error(`No channel with name "#${name}" could be found! (did you set it up yet?)`); return null; From f738bf44845ec0481aad052dc2fd2d487c97741f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 13:42:17 +0100 Subject: [PATCH 171/379] Method requires bigstring --- discord/util/find-channel-by-name.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/util/find-channel-by-name.ts b/discord/util/find-channel-by-name.ts index 857aa760..7669512a 100644 --- a/discord/util/find-channel-by-name.ts +++ b/discord/util/find-channel-by-name.ts @@ -11,7 +11,7 @@ import { Logger } from "../../logging/logger.ts"; * @param name */ export async function findChannelByName(guild: BigInt, name: string): Promise { - const channels = await Discord.getBot().helpers.getChannels(guild); + const channels = await Discord.getBot().helpers.getChannels(guild.toString()); if(!channels) { Logger.error(`Could not obtain channels for guild! (this is a bug!)`); return null; From df4b41b71a1d8b99b1a245d7dabecf12cb2c4906 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 13:42:46 +0100 Subject: [PATCH 172/379] Fix type --- discord/util/find-channel-by-name.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/util/find-channel-by-name.ts b/discord/util/find-channel-by-name.ts index 7669512a..6bc0d927 100644 --- a/discord/util/find-channel-by-name.ts +++ b/discord/util/find-channel-by-name.ts @@ -10,7 +10,7 @@ import { Logger } from "../../logging/logger.ts"; * @param guild * @param name */ -export async function findChannelByName(guild: BigInt, name: string): Promise { +export async function findChannelByName(guild: bigint, name: string): Promise { const channels = await Discord.getBot().helpers.getChannels(guild.toString()); if(!channels) { Logger.error(`Could not obtain channels for guild! (this is a bug!)`); From 078c7d27d89526576a63be152a8253f4b9d0a0ee Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 16:19:59 +0100 Subject: [PATCH 173/379] Add todo to find out types for spec --- communication/druid.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/communication/druid.ts b/communication/druid.ts index af50ee03..884ce601 100644 --- a/communication/druid.ts +++ b/communication/druid.ts @@ -1,7 +1,11 @@ export class Druid { + // TODO: Find out types of spec + // deno-lint-ignore no-explicit-any -- Will be added later private spec: any = null; + // deno-lint-ignore no-explicit-any -- Will be added later public set setSpec(spec: any) { this.spec = spec; } - public get getSpec() { return this.spec; } + // deno-lint-ignore no-explicit-any -- Will be added later + public get getSpec(): any { return this.spec; } public constructor( private readonly host: string, From f38a3372b5f912e654ce5beb7f91caeae351a5ce Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 16:20:32 +0100 Subject: [PATCH 174/379] Add types for Redis --- communication/redis.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/communication/redis.ts b/communication/redis.ts index 93b59d67..5c996c4a 100644 --- a/communication/redis.ts +++ b/communication/redis.ts @@ -1,8 +1,8 @@ -import { connect as redisConnect } from "https://deno.land/x/redis@v0.25.2/mod.ts" +import { connect as redisConnect, Redis as RedisConn } from "https://deno.land/x/redis@v0.25.2/mod.ts" import { Logger } from "../logging/logger.ts"; export class Redis { - private static connection: any = null; + private static connection: RedisConn|null = null; /** * Connect to a Redis node @@ -20,12 +20,11 @@ export class Redis { /** * Return the redis connection - * TODO: Find out type of Redis.connection * * @return any */ - public static getConnection(): any { + public static getConnection(): RedisConn { if(!Redis.connection) Logger.error(`Redis connection requested before connecting!`); - return Redis.connection; + return Redis.connection!; } } From 0fca0542c982b189df320c61caa50865f5f23175 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 16:38:03 +0100 Subject: [PATCH 175/379] Optimize snowflakeToDate a bit and write a test for it --- discord/mod.ts | 3 ++- discord/util/snowflake-to-date.ts | 7 +++---- tests/discord/utility.test.ts | 9 +++++++++ 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 tests/discord/utility.test.ts diff --git a/discord/mod.ts b/discord/mod.ts index e7afc197..e5e40865 100644 --- a/discord/mod.ts +++ b/discord/mod.ts @@ -21,4 +21,5 @@ export { snowflakeToDate } from "./util/snowflake-to-date.ts"; // Export Discord class export { Discord } from "./discord.ts"; - +// Export Constants +export const DISCORD_EPOCH: number = 1_420_070_400_000; diff --git a/discord/util/snowflake-to-date.ts b/discord/util/snowflake-to-date.ts index ff144062..434236ff 100644 --- a/discord/util/snowflake-to-date.ts +++ b/discord/util/snowflake-to-date.ts @@ -1,4 +1,4 @@ -export const DISCORD_EPOCH = 1420070400000; +import { DISCORD_EPOCH } from "../mod.ts"; /** * Turn a Discord snowflake into a date object. @@ -7,7 +7,6 @@ export const DISCORD_EPOCH = 1420070400000; * @param snowflake * @param epoch */ -export function snowflakeToDate(snowflake: any, epoch: number = DISCORD_EPOCH): Date { - const milliseconds = BigInt(snowflake) >> 22n; - return new Date(Number(milliseconds) + epoch); +export function snowflakeToDate(snowflake: bigint, epoch: number = DISCORD_EPOCH): Date { + return new Date(Number(snowflake >> 22n) + epoch); } diff --git a/tests/discord/utility.test.ts b/tests/discord/utility.test.ts new file mode 100644 index 00000000..bab0ba27 --- /dev/null +++ b/tests/discord/utility.test.ts @@ -0,0 +1,9 @@ +import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; +import { snowflakeToDate } from "../../discord/util/snowflake-to-date.ts"; + +Deno.test("Discord Utilities Test", async (t) => { + await t.step("snowflakeToDate", () => { + assertEquals(snowflakeToDate(91616138860978176n), new Date('2015-09-10T19:29:49.650Z')); + assertEquals(snowflakeToDate(1011419238923255838n),new Date('2022-08-22T23:38:57.820Z')); + }); +}); From e04626358828cc9f9acfaa3d51b5f57b404b4ce1 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 16:39:05 +0100 Subject: [PATCH 176/379] Make handlebars unable to return nothing --- webserver/renderers/handlebars.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index d6aa8341..4aa4c349 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -1,5 +1,4 @@ import { default as hbs } from "https://jspm.dev/handlebars@4.7.6"; -import { Logger } from "../../logging/logger.ts"; import { raise } from "../../error/raise.ts"; import { ViewVariable } from "../controller/controller.ts"; @@ -26,19 +25,15 @@ export class Handlebars { return compiled(vars); } - private static async getTemplate(path: string): Promise { + private static async getTemplate(path: string): Promise { // Make sure out template exists try { await Deno.stat(path); } catch(e) { - Logger.error(`Could not render handlebars template: Could not read template at "${path}"`, e.stack); - return; + throw new Error(`Could not render handlebars template: Could not read template at "${path}"`, e.stack); } - // Read our template - const template = await Deno.readTextFile(path); - - // Return the template - return template; + // Read and our template + return await Deno.readTextFile(path); } } From bf774d74b430948bb8f9b9bddc24a7eae7e36074 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 17:34:57 +0100 Subject: [PATCH 177/379] Make the linter a wee-bit less upset with me --- communication/couchdb.ts | 16 ++++++++++---- communication/druid.ts | 7 +++--- communication/loki.ts | 1 + communication/nut.ts | 34 ++++++++++++++++++++---------- communication/rcon.ts | 1 - core/configure.ts | 8 ++++++- discord/discord.ts | 1 + discord/event/dispatcher.ts | 8 ++++--- discord/interaction/dispatcher.ts | 8 ++++--- discord/util/find-role-by-name.ts | 2 +- logging/logger.ts | 11 +++++----- queue/queue.ts | 8 ++++--- security/hash.ts | 2 +- tests/common/configure.test.ts | 1 + utility/empty.ts | 1 + utility/text.ts | 2 +- utility/time-string.ts | 8 ++++--- webserver/controller/controller.ts | 14 +++++++----- webserver/pathToRegexp.ts | 3 ++- webserver/renderers/handlebars.ts | 1 + webserver/webserver.ts | 3 ++- websocket/events.ts | 2 ++ websocket/websocket.ts | 8 ++++--- 23 files changed, 99 insertions(+), 51 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 47a83f4d..a4ba2e4a 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -6,8 +6,9 @@ interface Auth { export interface CouchResponse { status: number; statusText: string; - data?: any; - error?: { + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used + data: any|null; + error: null|{ error: string; reason: string; }; @@ -70,6 +71,7 @@ export class CouchDB { * * @param data */ + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public async insert(data: any): Promise { return await this.raw('', data); } @@ -82,6 +84,7 @@ export class CouchDB { * @param revision * @param data */ + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public async update(id: string, revision: string, data: any): Promise { // Make sure the id and revision are set in the data if(!data['_id'] || data['_id'] !== id) data['_id'] = id; @@ -98,6 +101,7 @@ export class CouchDB { * @param id * @param data */ + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public async upsert(id: string, data: any): Promise { // Check if a document already exists // Insert a new document if not @@ -115,6 +119,7 @@ export class CouchDB { * Delete a document from the database. * * @param id + * @param revision */ public async delete(id: string, revision: string): Promise { return await this.raw(`${id}?rev=${revision}`, null, { method: 'DELETE' }); @@ -128,9 +133,10 @@ export class CouchDB { * @param body * @param overrides */ + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public async raw(endpoint: string, body: any = null, overrides: CouchOverrides = {}): Promise { // Start building opts - const opts: any = { + const opts = { method: overrides['method'] ? overrides['method'] : 'GET', headers: { Authorization: `Basic ${this.auth}`, @@ -153,9 +159,11 @@ export class CouchDB { if(opts.method !== 'HEAD') data = await resp.json(); // Prepare our CouchResponse - const couchResponse = { + const couchResponse: CouchResponse = { status: resp.status, statusText: resp.statusText, + data: null, + error: null, }; // Check whether we have an error diff --git a/communication/druid.ts b/communication/druid.ts index 884ce601..ab524a15 100644 --- a/communication/druid.ts +++ b/communication/druid.ts @@ -1,10 +1,9 @@ export class Druid { - // TODO: Find out types of spec - // deno-lint-ignore no-explicit-any -- Will be added later + // deno-lint-ignore no-explicit-any -- TODO private spec: any = null; - // deno-lint-ignore no-explicit-any -- Will be added later + // deno-lint-ignore no-explicit-any -- TODO public set setSpec(spec: any) { this.spec = spec; } - // deno-lint-ignore no-explicit-any -- Will be added later + // deno-lint-ignore no-explicit-any -- TODO public get getSpec(): any { return this.spec; } public constructor( diff --git a/communication/loki.ts b/communication/loki.ts index eb0bfb1f..211f3762 100644 --- a/communication/loki.ts +++ b/communication/loki.ts @@ -1,6 +1,7 @@ import { Logger } from "../logging/logger.ts"; export interface LokiStream { + // deno-lint-ignore no-explicit-any -- TODO stream: any; values: Array>; } diff --git a/communication/nut.ts b/communication/nut.ts index 65e2183c..b4528430 100644 --- a/communication/nut.ts +++ b/communication/nut.ts @@ -8,8 +8,9 @@ export class NutState { export class Nut { private host: string = ''; private port: number = 3493; - private client: any = null; + private client: Deno.TcpConn|null = null; private _status: number = NutState.IDLE; + // deno-lint-ignore no-explicit-any -- TODO private callback: any = null; private dataBuf: string = ''; @@ -33,6 +34,7 @@ export class Nut { this.onReceive(); } + // deno-lint-ignore no-explicit-any -- TODO public async send(cmd: string, callback: any) { if(this._status !== NutState.IDLE) throw new Error(`NUT not ready to send new data yet!`); this._status = NutState.WAITING; @@ -45,26 +47,25 @@ export class Nut { await this.client.write(data); } - public async close() { + public close() { //this.send(`LOGOUT`); this.client.close(); } private async onReceive() { + // deno-lint-ignore no-deprecated-deno-api -- TODO for await (const buffer of Deno.iter(this.client)) { this.dataBuf += new TextDecoder().decode(buffer); this.callback(this.dataBuf); } } - private onError(err: any) { - console.log(err); - } - public getLoad(name: string|undefined): Promise { if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); - return new Promise(async (resolve: any, reject: any) => { + // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO + return new Promise(async (resolve: any) => { + // deno-lint-ignore no-explicit-any -- TODO await this.send(`GET VAR ${name} ups.load`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) ups\.load "([0-9]+)"/.exec(data); @@ -91,7 +92,9 @@ export class Nut { public getPowerLimit(name: string|undefined): Promise { if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); - return new Promise(async (resolve: any, reject: any) => { + // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO + return new Promise(async (resolve: any) => { + // deno-lint-ignore no-explicit-any -- TODO await this.send(`GET VAR ${name} ups.realpower.nominal`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) ups\.realpower\.nominal "([0-9]+)"/.exec(data); @@ -117,7 +120,9 @@ export class Nut { public getCharge(name: string|undefined): Promise { if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); - return new Promise(async (resolve: any, reject: any) => { + // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO + return new Promise(async (resolve: any) => { + // deno-lint-ignore no-explicit-any -- TODO await this.send(`GET VAR ${name} battery.charge`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) battery\.charge "([0-9]+)"/.exec(data); @@ -143,7 +148,9 @@ export class Nut { public getRuntime(name: string|undefined): Promise { if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); - return new Promise(async (resolve: any, reject: any) => { + // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO + return new Promise(async (resolve: any) => { + // deno-lint-ignore no-explicit-any -- TODO await this.send(`GET VAR ${name} battery.runtime`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) battery\.runtime "([0-9]+)"/.exec(data); @@ -169,7 +176,9 @@ export class Nut { public getStatus(name: string|undefined): Promise { if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); - return new Promise(async (resolve: any, reject: any) => { + // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO + return new Promise(async (resolve: any) => { + // deno-lint-ignore no-explicit-any -- TODO await this.send(`GET VAR ${name} ups.status`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) ups\.status "([0-9]+)"/.exec(data); @@ -193,9 +202,12 @@ export class Nut { } public get UPSList() { + // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO return new Promise(async (resolve: any, reject: any) => { + // deno-lint-ignore no-explicit-any -- TODO await this.send(`LIST UPS`, (data: any) => { const dataArray = data.split('\n'); + // deno-lint-ignore no-explicit-any -- TODO const vars: any = {}; for (const line of dataArray) { // Check if we have an error diff --git a/communication/rcon.ts b/communication/rcon.ts index 8d4d5bbd..2745fac0 100644 --- a/communication/rcon.ts +++ b/communication/rcon.ts @@ -86,7 +86,6 @@ export class RCON { private async recv(): Promise { const data = new Buffer(2048); // TODO: Fix await this.conn.read(data); - const length = data.readInt32LE(0); const id = data.readInt32LE(4); const type = data.readInt32LE(8); diff --git a/core/configure.ts b/core/configure.ts index a573c77d..3284220e 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -6,6 +6,7 @@ const defaults = [ ]; export class Configure { + // deno-lint-ignore no-explicit-any -- Arbitrary data may be used private static config = new Map(defaults); private static hasLoaded = false; @@ -23,7 +24,7 @@ export class Configure { // Make sure our file exists try { await Deno.stat(`${Deno.cwd()}/config.json`); - } catch(e) { + } catch(_e) { Logger.warning(`Could not find file "config.json" at "${Deno.cwd()}". Configure will be empty!`); Configure.hasLoaded = true; return; @@ -53,6 +54,7 @@ export class Configure { * @param defaultValue Default value to return when no result was found * @returns any */ + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static get(key: string, defaultValue: any = null): any { // Check if the key exists. // If not: return the default value @@ -68,6 +70,7 @@ export class Configure { * @param value * @returns void */ + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static set(key: string, value: any): void { Configure.config.set(key, value); } @@ -82,6 +85,7 @@ export class Configure { return Configure.config.has(key); } + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static consume(key: string, defaultValue: any = null): any { // Check if the key exists, if not, return the default value if(!Configure.config.has(key)) return defaultValue; @@ -111,6 +115,7 @@ export class Configure { * * @returns ConfigureItem[] */ + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static dump(): Map { return Configure.config; } @@ -130,6 +135,7 @@ export class Configure { * If you do not want to keep the defaults, use "Configure.clear()" instead. */ public static reset(): void { + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used Configure.config = new Map(defaults); } } diff --git a/discord/discord.ts b/discord/discord.ts index a46bde26..03076fa9 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -60,6 +60,7 @@ export class Discord { channelUpdate(_bot, channel) { EventDispatcher.dispatch('ChannelUpdate', channel); }, + // deno-lint-ignore no-explicit-any -- Set by Discordeno debug(text, ...args: any[]) { EventDispatcher.dispatch('Debug', { text: text, args: args }); }, diff --git a/discord/event/dispatcher.ts b/discord/event/dispatcher.ts index f9705175..d3cbf238 100644 --- a/discord/event/dispatcher.ts +++ b/discord/event/dispatcher.ts @@ -10,6 +10,7 @@ interface EventConfig { export class EventDispatcher { private static list: EventConfig[] = []; + // deno-lint-ignore no-explicit-any -- TODO private static handlers: any = {}; /** @@ -33,7 +34,7 @@ export class EventDispatcher { * Import an event handler and add it to the list of handlers * TODO: Make sure class implements Event * - * @param EventConfig event + * @param event * @returns Promise */ public static async add(event: EventConfig): Promise { @@ -57,10 +58,11 @@ export class EventDispatcher { /** * Run an instance of the Feature handler * - * @param string Event - * @param any data + * @param event + * @param data * @returns Promise */ + // deno-lint-ignore no-explicit-any -- TODO public static async dispatch(event: string, data: any = {}): Promise { // Get the event handler const handler = EventDispatcher.getHandler(event); diff --git a/discord/interaction/dispatcher.ts b/discord/interaction/dispatcher.ts index 23967ac8..cfa778e9 100644 --- a/discord/interaction/dispatcher.ts +++ b/discord/interaction/dispatcher.ts @@ -1,4 +1,4 @@ -import { ApplicationCommandOption, ApplicationCommandTypes } from "../mod.ts"; +import {ApplicationCommandOption, ApplicationCommandTypes, BigString} from "../mod.ts"; import { Discord } from "../discord.ts"; import { Logger } from "../../logging/logger.ts"; import { File } from "../../filesystem/file.ts"; @@ -17,6 +17,7 @@ export interface InteractionConfig { export class InteractionDispatcher { private static _interactionsDir = `${Deno.cwd()}/src/interactions`; private static list: InteractionConfig[] = []; + // deno-lint-ignore no-explicit-any -- TODO private static handlers: any = {}; /** @@ -42,9 +43,9 @@ export class InteractionDispatcher { * @param opts * @returns Promise */ - public static async update(opts: any): Promise { + public static async update(opts: {guildId: bigint|BigString}): Promise { try { - await Discord.getBot()?.helpers.upsertGuildApplicationCommands(opts.guildId, InteractionDispatcher.getInteractions()); + await Discord.getBot()?.helpers.upsertGuildApplicationCommands(opts.guildId.toString(), InteractionDispatcher.getInteractions()); } catch(e) { Logger.error(`Could not update interactions: ${e.message}`); } @@ -75,6 +76,7 @@ export class InteractionDispatcher { * @param data * @returns Promise */ + // deno-lint-ignore no-explicit-any -- TODO public static async dispatch(interaction: string, data: any = {}): Promise { // Get the handler const handler = InteractionDispatcher.getHandler(interaction); diff --git a/discord/util/find-role-by-name.ts b/discord/util/find-role-by-name.ts index ca05031f..f5daabe4 100644 --- a/discord/util/find-role-by-name.ts +++ b/discord/util/find-role-by-name.ts @@ -11,7 +11,7 @@ import empty from "../../utility/empty.ts"; * @param expiry Expiry time. Pass null to disable caching. * @returns Promise */ -export async function findRoleByName(guild: BigInt, roleName: string, expiry: string|null = `+1 hour`): Promise { +export async function findRoleByName(guild: bigint, roleName: string, expiry: string|null = `+1 hour`): Promise { if(!empty(expiry) && !Cache.expired(`role name ${roleName}`)) { return Cache.get(`role name ${roleName}`) as Role; } diff --git a/logging/logger.ts b/logging/logger.ts index fb082118..795e3448 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -4,10 +4,10 @@ import { cyan, yellow, red, magenta, bold } from "https://deno.land/std@0.117.0/ type LogLevels = "info"|"warning"|"error"|"debug"; type Handlers = { - info: (message: string) => any; - warning: (message: string) => any; - error: (message: string, stack: string|null) => any; - debug: (message: string) => any; + info: (message: string) => void; + warning: (message: string) => void; + error: (message: string, stack: string|null) => void; + debug: (message: string) => void; }; const handlers: Handlers = { @@ -50,7 +50,8 @@ export class Logger { * @param level {LogLevels} * @param handler {any} */ - public static setHandler(level: LogLevels, handler: any): void { Logger._handlers[level] = handler; } + // deno-lint-ignore ban-types -- TODO + public static setHandler(level: LogLevels, handler: Function): void { Logger._handlers[level] = handler; } /** * Write an info message to the console diff --git a/queue/queue.ts b/queue/queue.ts index c5e93a1f..3e87526b 100644 --- a/queue/queue.ts +++ b/queue/queue.ts @@ -2,6 +2,7 @@ import { Logger } from "../logging/logger.ts"; interface QueueItem { weight?: number; + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used data: any; } @@ -86,21 +87,21 @@ export class Queue { // Add item to the queue based on the scheduler used switch(this.scheduler) { case Scheduler.FIFO: - if(item.hasOwnProperty('weight')) { + if('weight' in item) { Logger.debug('A weight was set without the weighted scheduler, removing it...'); delete item.weight; } this.items.push(item); break; case Scheduler.LIFO: - if(item.hasOwnProperty('weight')) { + if('weight' in item) { Logger.debug('A weight was set without the weighted scheduler, removing it...'); delete item.weight; } this.items.unshift(item); break; case Scheduler.WEIGHTED: - if(!item.hasOwnProperty('weight')) { + if(!('weight' in item)) { Logger.debug('No weight was set with weighted scheduler, defaulting to 0...'); item.weight = 0; } @@ -135,6 +136,7 @@ export class Queue { // Check if all keys exists and if they have the same value for(const key of itemKeys) { + // deno-lint-ignore no-prototype-builtins -- TODO if(!queued.data.hasOwnProperty(key)) return false; if(queued.data[key] !== item.data[key]) return false; } diff --git a/security/hash.ts b/security/hash.ts index 87342388..cc676d44 100644 --- a/security/hash.ts +++ b/security/hash.ts @@ -48,7 +48,7 @@ export const INSECURE_ALGORITHMS: string[] = [ ]; export class Hash { - private result: any; + private result: ArrayBuffer; constructor( private input: string, diff --git a/tests/common/configure.test.ts b/tests/common/configure.test.ts index ed4fa036..7dfb3bd3 100644 --- a/tests/common/configure.test.ts +++ b/tests/common/configure.test.ts @@ -19,6 +19,7 @@ Deno.test("Configure Test", () => { // Make sure clearing works Configure.set('test3', 'chomp'); Configure.clear(); + // deno-lint-ignore no-explicit-any -- Arbitrary data may be used assertEquals(Configure.dump(), new Map()); // Make sure default values work on get and consume diff --git a/utility/empty.ts b/utility/empty.ts index b211d961..d768262b 100644 --- a/utility/empty.ts +++ b/utility/empty.ts @@ -4,6 +4,7 @@ * @param input * @returns boolean */ +// deno-lint-ignore no-explicit-any -- Any arbitrary data may be used export default function empty(input: string|any[]|null): boolean { if(!input) return true; if(typeof input === "string") return input === ""; diff --git a/utility/text.ts b/utility/text.ts index 3000238c..a6cacc33 100644 --- a/utility/text.ts +++ b/utility/text.ts @@ -15,7 +15,7 @@ export class Text { public static tokenize(input: string, limit = 3): string[] { const tokens = input.split(" "); if(tokens.length > limit) { - let ret = tokens.splice(0, limit); + const ret = tokens.splice(0, limit); ret.push(tokens.join(" ")); return ret; } diff --git a/utility/time-string.ts b/utility/time-string.ts index 3a965292..fbc78b33 100644 --- a/utility/time-string.ts +++ b/utility/time-string.ts @@ -73,7 +73,8 @@ function parseNumberFormat(digit: string, unit: string): number { * @param parts * @returns number */ -export function T(strIn: TemplateStringsArray, ...parts: any[]) { +// deno-lint-ignore no-explicit-any -- TODO +export function T(strIn: TemplateStringsArray, ...parts: any[]): number { const str = String.raw(strIn, parts).toLowerCase().replace(/\s/g, ''); const parsed = [...str.matchAll(TimeRegexp)]; if (parsed.length === 0) @@ -87,11 +88,12 @@ export function T(strIn: TemplateStringsArray, ...parts: any[]) { /** * Takes a time string and turns it into round seconds - * + * * @param strIn * @param parts * @returns number */ -export function _T(strIn: TemplateStringsArray, ...parts: any[]) { +// deno-lint-ignore no-explicit-any -- TODO +export function _T(strIn: TemplateStringsArray, ...parts: any[]): number { return Math.round(T(strIn, parts) / 1000); } diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 538aff24..a6bfb2d7 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -109,20 +109,24 @@ export class Controller { let body: string|Uint8Array = ''; const canCompress = true; switch(this.getResponse().getHeaderLine('Content-Type').toLowerCase()) { - case 'application/json': + case 'application/json': { body = JSON.stringify(this._vars['data']); break; - case 'text/plain': + } + case 'text/plain': { body = this._vars['message'] as string; break; - case 'text/html': + } + case 'text/html': { const controller = Inflector.lcfirst(this.getRequest().getRoute().getController()); const action = this.getRequest().getRoute().getAction(); - body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars) ?? raise('Could not render handlebars'); + body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars); break; - case 'application/octet-stream': + } + case 'application/octet-stream': { body = this._vars['data'] as Uint8Array; break; + } } // Check if we can compress with Brotli diff --git a/webserver/pathToRegexp.ts b/webserver/pathToRegexp.ts index 57e045c2..abeb375f 100644 --- a/webserver/pathToRegexp.ts +++ b/webserver/pathToRegexp.ts @@ -274,7 +274,8 @@ export function tokensToFunction

( return new RegExp(`^(?:${token.pattern})$`, reFlags); } }); - + + // deno-lint-ignore no-explicit-any -- TODO return (data: Record | null | undefined) => { let path = ""; diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index 4aa4c349..4ed4e73e 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -3,6 +3,7 @@ import { raise } from "../../error/raise.ts"; import { ViewVariable } from "../controller/controller.ts"; interface CacheItem { + // deno-lint-ignore ban-types -- TODO [key: string]: Function; } diff --git a/webserver/webserver.ts b/webserver/webserver.ts index 959750bd..2b868d52 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -3,7 +3,7 @@ import { Router } from "./routing/router.ts"; import { StatusCodes } from "./http/status-codes.ts"; export class Webserver { - private server: any = null; + private server: Deno.Listener|null = null; constructor( private readonly port: number = 80 @@ -23,6 +23,7 @@ export class Webserver { private async serve(conn: Deno.Conn) { // Upgrade the connection to HTTP + // deno-lint-ignore no-deprecated-deno-api -- TODO const httpConn: Deno.HttpConn = Deno.serveHttp(conn); // Handle each request for this connection diff --git a/websocket/events.ts b/websocket/events.ts index 35463e5d..2f283ddd 100644 --- a/websocket/events.ts +++ b/websocket/events.ts @@ -7,6 +7,7 @@ interface IEvent { export class Events { private static list: IEvent[] = []; + // deno-lint-ignore no-explicit-any -- TODO private static handlers: any = {}; public static getEvents() { return Events.list; } @@ -26,6 +27,7 @@ export class Events { Events.list.push(event); } + // deno-lint-ignore no-explicit-any -- TODO public static async dispatch(event: string, data: any = {}) { // Get the event handler const handler = Events.getHandler(event); diff --git a/websocket/websocket.ts b/websocket/websocket.ts index 6453bc08..23176041 100644 --- a/websocket/websocket.ts +++ b/websocket/websocket.ts @@ -33,14 +33,15 @@ export class Websocket { }); } - public async broadcast(eventString: string, data: any) { + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used + public broadcast(eventString: string, data: any) { // Make sure the server has started if(!this.server) return; // Loop over each client // Check whether they are still alive // Send the event to the clients that are still alive - for(let client of this.server.clients) { + for(const client of this.server.clients) { if(!client) continue; if(client.isClosed) continue; client.send(JSON.stringify({ @@ -74,7 +75,8 @@ export class Websocket { } } - private async handleEvent(event: string, data: any = []) { + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used + private async handleEvent(event: string, data: any = {}) { const handler = Events.getHandler(event); if(!handler) return Logger.warning(`Event "${event}" does not exists! (did you register it?)`); From 52bebc7d1ae0f96ca5d3bb5a1375392365e774c3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 17:36:15 +0100 Subject: [PATCH 178/379] Upgrade Deno version --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4be8c613..d3a27986 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: - name: Set up Deno uses: denoland/setup-deno@v1 with: - deno-version: "1.30.0" + deno-version: "1.40.0" - name: Lint run: deno lint - name: Run tests From 2910e9d17f071c4fe1fb5ae52a8cd7390709925d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 17:37:24 +0100 Subject: [PATCH 179/379] Update "raise" --- error/raise.ts | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/error/raise.ts b/error/raise.ts index 4de9dee5..3060889b 100644 --- a/error/raise.ts +++ b/error/raise.ts @@ -1,19 +1,25 @@ /** - * Utility function that literally just throws an error. - * + * Utility function that throws an error. + * Band-aid for JS not supporting throwing in null-coalescing. + * * @param err * @param type */ -export function raise(err: string, type: string|Function|'Error' = 'Error'): never { +// deno-lint-ignore no-explicit-any ban-types -- TODO +export function raise(err: string, type: string|(new (...args: any[]) => TError)|'Error' = 'Error'){ // Check if we want to throw a regular error if(type === "Error") throw new Error(err); - // Check if we want to throw a specific error class - if(typeof type === "function") throw new type(err); + // Check if we want to throw a specific name only + if(typeof type === "string") { + if(type.slice(-5).toLowerCase() !== "error") type = `${type}Error`; + const e = new Error(err); + e.name = type as string; + throw e; + } - // Build a custom error and throw it - if(type.slice(-5).toLowerCase() !== "error") type = `${type}Error`; - const e = new Error(err); - e.name = type; - throw e; + // Check if we want to throw a specific error class + if(type.prototype instanceof Error) throw new type(err); } + +//raise('Test', 'BlahError'); From b50ac69ce44eb18d17bbff8ad3b98d86de1e227f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 30 Jan 2024 17:39:03 +0100 Subject: [PATCH 180/379] Remove unused ignore --- error/raise.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/error/raise.ts b/error/raise.ts index 3060889b..1b52d93c 100644 --- a/error/raise.ts +++ b/error/raise.ts @@ -5,7 +5,7 @@ * @param err * @param type */ -// deno-lint-ignore no-explicit-any ban-types -- TODO +// deno-lint-ignore no-explicit-any -- TODO export function raise(err: string, type: string|(new (...args: any[]) => TError)|'Error' = 'Error'){ // Check if we want to throw a regular error if(type === "Error") throw new Error(err); From 2ebd5bd89ff92afec2b53ad281e82f00897c95cb Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 16:46:06 +0100 Subject: [PATCH 181/379] Remove obsolete events --- discord/discord.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/discord/discord.ts b/discord/discord.ts index 03076fa9..2fd13f58 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -82,9 +82,6 @@ export class Discord { guildEmojisUpdate(_bot, payload) { EventDispatcher.dispatch('guildEmojisUpdate', payload); }, - guildLoaded(_bot, data) { - EventDispatcher.dispatch('GuildLoaded', data); - }, guildMemberAdd(_bot, member, user) { EventDispatcher.dispatch('GuildMemberAdd', { member: member, user: user }); }, @@ -203,9 +200,6 @@ export class Discord { typingStart(_bot, payload) { EventDispatcher.dispatch('TypingStart', payload); }, - voiceChannelLeave(_bot, voiceState, guild, channel) { - EventDispatcher.dispatch('VoiceChannelLeave', { voiceState: voiceState, guild: guild, channel: channel }); - }, voiceServerUpdate(_bot, payload) { EventDispatcher.dispatch('VoiceServerUpdate', payload); }, From 122525b452ecd234a918a724ae3d3c8b2e9ec9c8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 16:47:07 +0100 Subject: [PATCH 182/379] Make time public --- logging/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging/logger.ts b/logging/logger.ts index 795e3448..e63f9f0a 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -96,7 +96,7 @@ export class Logger { * * @returns {string} The formatted time */ - protected static time(): string { + public static time(): string { return new Time().format(Configure.get('logger.timeformat', 'yyyy/MM/dd HH:mm:ss')); } } From 0bf361d0c9fccb547e8f425bef1624805a5898a6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 16:59:18 +0100 Subject: [PATCH 183/379] Fix errors where Discord.getBot() could possibly be undefined --- discord/discord.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/discord/discord.ts b/discord/discord.ts index 2fd13f58..48593c4b 100644 --- a/discord/discord.ts +++ b/discord/discord.ts @@ -27,7 +27,10 @@ export class Discord { /** * Return the instance of the Discord bot connection */ - public static getBot(): Bot|BotWithCache|undefined { return Discord.bot; } + public static getBot(): Bot|BotWithCache { + if(!Discord.bot) throw new Error('Bot was not properly initialized!'); + return Discord.bot; + } public constructor(opts: DiscordInitOpts) { // Make sure required parameters are present From 9edeed3dac24f02807cc99071b0dc4fd5e9637ca Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 18:18:27 +0100 Subject: [PATCH 184/379] Fix cache error and ignore TS error --- discord/util/find-role-by-name.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/discord/util/find-role-by-name.ts b/discord/util/find-role-by-name.ts index f5daabe4..db98921f 100644 --- a/discord/util/find-role-by-name.ts +++ b/discord/util/find-role-by-name.ts @@ -17,7 +17,8 @@ export async function findRoleByName(guild: bigint, roleName: string, expiry: st } // Get a list of all roles for the guild - const roles = Discord.getBot().roles + // @ts-ignore Using null-coalescing to check whether cache is enabled + const roles = Discord.getBot().guilds.get(guild)?.roles ?? await Discord.getBot().helpers.getRoles(guild); if(!roles) { Logger.error(`Could not obtain roles for guild! (this is a bug!)`); From 3a88a28e2d6fa4bc49210085da3ad373e2b16610 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 18:18:41 +0100 Subject: [PATCH 185/379] Fix variable name error --- discord/interaction/dispatcher.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/interaction/dispatcher.ts b/discord/interaction/dispatcher.ts index cfa778e9..e81f2399 100644 --- a/discord/interaction/dispatcher.ts +++ b/discord/interaction/dispatcher.ts @@ -133,7 +133,7 @@ export class InteractionDispatcher { // Make sure module has a "config" exposed if(!('config' in module)) { - Logger.warning(`Could not find config in "${interaction.name}", skipping...`); + Logger.warning(`Could not find config in "${name}Interaction", skipping...`); continue; } From bc4f784485b624fa52caea4edd736ef99d0179d7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 18:20:06 +0100 Subject: [PATCH 186/379] Add type to dispatcher --- discord/interaction/dispatcher.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/discord/interaction/dispatcher.ts b/discord/interaction/dispatcher.ts index e81f2399..f2dc79c8 100644 --- a/discord/interaction/dispatcher.ts +++ b/discord/interaction/dispatcher.ts @@ -1,4 +1,4 @@ -import {ApplicationCommandOption, ApplicationCommandTypes, BigString} from "../mod.ts"; +import {ApplicationCommandOption, ApplicationCommandTypes, BigString, DiscordInteraction} from "../mod.ts"; import { Discord } from "../discord.ts"; import { Logger } from "../../logging/logger.ts"; import { File } from "../../filesystem/file.ts"; @@ -76,8 +76,7 @@ export class InteractionDispatcher { * @param data * @returns Promise */ - // deno-lint-ignore no-explicit-any -- TODO - public static async dispatch(interaction: string, data: any = {}): Promise { + public static async dispatch(interaction: string, data: DiscordInteraction = {}): Promise { // Get the handler const handler = InteractionDispatcher.getHandler(interaction); if(!handler) { From 7c98a331be3438484eab7ccab50624e3028f6902 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 18:20:14 +0100 Subject: [PATCH 187/379] Add more types --- discord/interaction/interaction.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/discord/interaction/interaction.ts b/discord/interaction/interaction.ts index 94a39349..ac56230f 100644 --- a/discord/interaction/interaction.ts +++ b/discord/interaction/interaction.ts @@ -1,10 +1,10 @@ -import { Discord } from "../mod.ts"; +import {Discord, DiscordInteraction, InteractionCallbackData, InteractionResponse} from "../mod.ts"; export class Interaction { - protected interaction: unknown; + protected interaction: DiscordInteraction; private _hasReplied: boolean = false; - public constructor(opts: unknown) { + public constructor(opts: {interaction: DiscordInteraction}) { this.interaction = opts.interaction; } @@ -21,12 +21,12 @@ export class Interaction { * * @param data */ - protected async respond(data: unknown): Promise { + protected async respond(data: InteractionResponse|InteractionCallbackData): Promise { if(!this._hasReplied) { await Discord.getBot().helpers.sendInteractionResponse( this.interaction.id, this.interaction.token, - data + data as InteractionResponse ); this._hasReplied = true; return; @@ -34,7 +34,7 @@ export class Interaction { await Discord.getBot().helpers.editOriginalInteractionResponse( this.interaction.token, - data + data as InteractionCallbackData ); } } From ddcbbfef84eb13688398cb825fd0af35431756bc Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 18:22:57 +0100 Subject: [PATCH 188/379] Do not allow empty interaction data --- discord/interaction/dispatcher.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/interaction/dispatcher.ts b/discord/interaction/dispatcher.ts index f2dc79c8..6138a0e2 100644 --- a/discord/interaction/dispatcher.ts +++ b/discord/interaction/dispatcher.ts @@ -76,7 +76,7 @@ export class InteractionDispatcher { * @param data * @returns Promise */ - public static async dispatch(interaction: string, data: DiscordInteraction = {}): Promise { + public static async dispatch(interaction: string, data: DiscordInteraction): Promise { // Get the handler const handler = InteractionDispatcher.getHandler(interaction); if(!handler) { From 15eb66f31260f42f79dd35d9b69d7b54e38385e2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 18:25:17 +0100 Subject: [PATCH 189/379] TSIgnore error --- core/cache.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/cache.ts b/core/cache.ts index e26922ff..d7b7639d 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -142,4 +142,5 @@ export class Cache { } // Sweep cache every hour +// @ts-ignore It's a function not a type Cron('1 0 * * * *', () => Cache.sweep()); From eaca2577f761819b30f2a9e478d0f46f278ac96f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 18:29:24 +0100 Subject: [PATCH 190/379] Just ts-ignore a few things into the TODO list --- discord/interaction/builder.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/discord/interaction/builder.ts b/discord/interaction/builder.ts index e1467260..b34c3b3e 100644 --- a/discord/interaction/builder.ts +++ b/discord/interaction/builder.ts @@ -32,12 +32,14 @@ export class InteractionBuilder { } public addSubcommand(command: (command: InteractionSubcommandBuilder) => InteractionSubcommandBuilder): InteractionBuilder { + // @ts-ignore TODO: Figure out why this throws an error during tests this._options.push(command(new InteractionSubcommandBuilder())); return this; } public addOption(option: (option: InteractionOptionBuilder) => void): InteractionBuilder { + // @ts-ignore TODO: Figure out why this throws an error during tests this._options.push(option(new InteractionOptionBuilder())); return this; @@ -54,6 +56,7 @@ export class InteractionBuilder { // Add data for our options for(const option of this._options) { + // @ts-ignore TODO: Figure out why this throws an error during tests data.options.push(option.toJSON()); } @@ -86,6 +89,7 @@ export class InteractionSubcommandBuilder { } public addOption(option: (option: InteractionOptionBuilder) => void): InteractionSubcommandBuilder { + // @ts-ignore TODO: Figure out why this throws an error during tests this._options.push(option(new InteractionOptionBuilder())); return this; @@ -102,6 +106,7 @@ export class InteractionSubcommandBuilder { // Add data for our options for(const option of this._options) { + // @ts-ignore TODO: Figure out why this throws an error during tests data.options.push(option.toJSON()); } From 827a7c24f10d3e6af9657c194c70454ef6ccda93 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 20:00:44 +0100 Subject: [PATCH 191/379] Fix error when assigning new Configure --- core/configure.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/configure.ts b/core/configure.ts index 3284220e..41ef600b 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,13 +1,13 @@ import { Logger } from "../logging/logger.ts"; -const defaults = [ +const defaults = new Map([ ['debug', false], - ['error_log', `${Deno.cwd()}/logs/error.log`] -]; + ['error_log', `${Deno.cwd()}/logs/error.log`], +]); export class Configure { // deno-lint-ignore no-explicit-any -- Arbitrary data may be used - private static config = new Map(defaults); + private static config: Map = defaults; private static hasLoaded = false; /** @@ -136,6 +136,6 @@ export class Configure { */ public static reset(): void { // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - Configure.config = new Map(defaults); + Configure.config = defaults; } } From 3e60952e30f42d70e97f9af4b5df67cbc02c60b9 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 20:01:00 +0100 Subject: [PATCH 192/379] No longer use env for debug logging --- logging/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging/logger.ts b/logging/logger.ts index e63f9f0a..00ec3efa 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -35,7 +35,7 @@ const handlers: Handlers = { console.error(output); }, debug: (message: string): void => { - if(Deno.env.get('DEBUG') == "true" || Configure.get('debug', false)) { + if(Configure.get('debug', false)) { console.log(`[${Logger.time()}] ${magenta('DEBUG')} > ${message}`); } } From cd931161cbcc3313b72cdc65641c247bb738544b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 20:01:10 +0100 Subject: [PATCH 193/379] Add TODO item --- logging/logger.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/logging/logger.ts b/logging/logger.ts index 00ec3efa..f9ee400e 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -50,6 +50,7 @@ export class Logger { * @param level {LogLevels} * @param handler {any} */ + // @ts-ignore TODO: Figure out how to replace Function with something more sane // deno-lint-ignore ban-types -- TODO public static setHandler(level: LogLevels, handler: Function): void { Logger._handlers[level] = handler; } From dfeb05d37e9d95b73e71474d575e3792d5d3753b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 20:01:21 +0100 Subject: [PATCH 194/379] Make LogLevels dynamic --- logging/logger.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/logging/logger.ts b/logging/logger.ts index f9ee400e..266545e7 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -9,6 +9,7 @@ type Handlers = { error: (message: string, stack: string|null) => void; debug: (message: string) => void; }; +type LogLevels = keyof Handlers; const handlers: Handlers = { info: (message: string): void => { console.log(`[${Logger.time()}] ${cyan('INFO')} > ${message}`); }, From 738faf67434635b04e527a4dc1fe7cfa0a62c9bc Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 20:02:14 +0100 Subject: [PATCH 195/379] Forgotten in previous commit --- logging/logger.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/logging/logger.ts b/logging/logger.ts index 266545e7..d30e8198 100644 --- a/logging/logger.ts +++ b/logging/logger.ts @@ -2,7 +2,6 @@ import { Time } from "../utility/time.ts"; import { Configure } from "../core/configure.ts"; import { cyan, yellow, red, magenta, bold } from "https://deno.land/std@0.117.0/fmt/colors.ts"; -type LogLevels = "info"|"warning"|"error"|"debug"; type Handlers = { info: (message: string) => void; warning: (message: string) => void; From 02fbd5d0f0a2e00dfdd91b3ec7ca0dab5c83182d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 20:03:50 +0100 Subject: [PATCH 196/379] Disable explicit any --- core/configure.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/configure.ts b/core/configure.ts index 41ef600b..254cfa21 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,5 +1,6 @@ import { Logger } from "../logging/logger.ts"; +// deno-lint-ignore no-explicit-any -- Arbitrary data may be used const defaults = new Map([ ['debug', false], ['error_log', `${Deno.cwd()}/logs/error.log`], @@ -135,7 +136,6 @@ export class Configure { * If you do not want to keep the defaults, use "Configure.clear()" instead. */ public static reset(): void { - // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used Configure.config = defaults; } } From f6afce350a7bf0e52b02b94f58c5d91b42ea8816 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 1 Feb 2024 20:05:18 +0100 Subject: [PATCH 197/379] Update test to handle linting and testing seperately --- .github/workflows/test.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d3a27986..f4eb08f0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,7 +5,7 @@ on: pull_request: branches: [main] jobs: - test: + lint: runs-on: ubuntu-latest steps: - name: Clone repository @@ -18,5 +18,16 @@ jobs: deno-version: "1.40.0" - name: Lint run: deno lint + test: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v3 + with: + submodules: true + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: "1.40.0" - name: Run tests run: deno test --allow-read --allow-env From d93ef8dc711b7ab224ef84d56d4007791f0984d9 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 2 Feb 2024 00:51:47 +0100 Subject: [PATCH 198/379] Remove env access during test --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f4eb08f0..2cbe9c72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,4 +30,4 @@ jobs: with: deno-version: "1.40.0" - name: Run tests - run: deno test --allow-read --allow-env + run: deno test --allow-read From 1f35ac3c10be371af0ffef46de351f5aedb4328b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 2 Feb 2024 01:29:43 +0100 Subject: [PATCH 199/379] Update raise function and add tests (Closes #11) --- error/raise.ts | 30 ++++++++++++++++-------------- tests/error/raise.test.ts | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 tests/error/raise.test.ts diff --git a/error/raise.ts b/error/raise.ts index 1b52d93c..584329c5 100644 --- a/error/raise.ts +++ b/error/raise.ts @@ -5,21 +5,23 @@ * @param err * @param type */ -// deno-lint-ignore no-explicit-any -- TODO -export function raise(err: string, type: string|(new (...args: any[]) => TError)|'Error' = 'Error'){ - // Check if we want to throw a regular error - if(type === "Error") throw new Error(err); - - // Check if we want to throw a specific name only - if(typeof type === "string") { - if(type.slice(-5).toLowerCase() !== "error") type = `${type}Error`; - const e = new Error(err); - e.name = type as string; +export function raise(err: string, type: string|(new (err: string) => CustomError)|'Error' = 'Error'){ + // Check if we want to throw a specific class + if(typeof type === 'function' && type.prototype instanceof Error) { + const e = new type(err); + Error.captureStackTrace(e, raise); + e.name = type.name; throw e; } - // Check if we want to throw a specific error class - if(type.prototype instanceof Error) throw new type(err); + // Initialize regular error + // Then add our stacktrace + const e = new Error(err); + Error.captureStackTrace(e, raise); + + // Check if we want to change the name + if(type !== "Error") e.name = (type as string).slice(-5).toLowerCase() !== "error" ? `${type}Error`: type as string; + + // Throw the error + throw e; } - -//raise('Test', 'BlahError'); diff --git a/tests/error/raise.test.ts b/tests/error/raise.test.ts new file mode 100644 index 00000000..04ccc994 --- /dev/null +++ b/tests/error/raise.test.ts @@ -0,0 +1,19 @@ +import { assertThrows } from "https://deno.land/std@0.152.0/testing/asserts.ts"; +import { raise } from "../../error/raise.ts"; + +class CustomError extends Error { + constructor(public message: string) { + super(message); + } +} + +Deno.test("Errors Test", () => { + // Check with a "simple" raise + assertThrows(() => raise('Some Error Message'), Error, 'Some Error Message'); + + // Check with custom Error type (via string) + assertThrows(() => raise('Some Error Message', 'CustomError'), Error, 'Some Error Message'); + + // Check with custom Error type (via class) + assertThrows(() => raise('Some Error Message', CustomError), CustomError, 'Some Error Message'); +}); From 065d4b71347bddde2281f8547672fe0254f303a2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 2 Feb 2024 12:27:06 +0100 Subject: [PATCH 200/379] Document raise function --- docs/error/raise.md | 64 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/docs/error/raise.md b/docs/error/raise.md index 64f43ee3..122beb8b 100644 --- a/docs/error/raise.md +++ b/docs/error/raise.md @@ -1 +1,65 @@ # raise + +Utility function that provides a band-aid for ES' shortcoming on not allowing `throw` statements during null-coalescing like, for example, PHP can do. + +```php +// PHP Example +$myVar = null ?? throw new Exception('Error Message'); +``` + +```ts +// TS Example +const myVar = null ?? throw new Error('Error Message'); // Expression expected +``` + +## Getting Started + +First, import the function as follows: +```ts +import { raise } from "https://deno.land/x/chomp/error/raise.ts"; +``` + +Then you can use it in your chains as follows: +```ts +const myVar = null ?? raise('Error Message'); +``` + +## Using Custom Error Types + +By default, the `raise` function will throw a "standard" `Error`: +``` +error: Uncaught (in promise) Error: Error Message +``` + +However, it may be desirable to be able to be more specific in what error has happened: +To do this, you can easily pass a name for the error to `raise`: + +```ts +const myVar = null ?? raise('Error Message', 'CustomError'); +``` +``` +error: Uncaught (in promise) CustomError: Error Message +``` + +Additionally, you can ommit the "Error" part in the name as this will be automatically added: +```ts +const myVar = null ?? raise('Error Message', 'Custom'); +``` +``` +error: Uncaught (in promise) CustomError: Error Message +``` + +If you need more flexibility, you can pass an `Error`-class to `raise` instead: +```ts +class CustomError extends Error { + constructor(public message: string) { + super(message); + } +} + +const myVar = null ?? raise('Error Message', CustomError); +``` + +``` +error: Uncaught (in promise) CustomError: Error Message +``` From dd75073b7e6199d05b354ebf81af93539aa94998 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 2 Feb 2024 12:41:34 +0100 Subject: [PATCH 201/379] Finish documenting configure --- docs/core/configure.md | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/docs/core/configure.md b/docs/core/configure.md index 93244b95..9418fdfe 100644 --- a/docs/core/configure.md +++ b/docs/core/configure.md @@ -43,16 +43,54 @@ const myConst = Configure.get('app configure item', 'default value'); ## Setting or updating an item in the Configure +Sometimes you may want to set or update an item during runtime. +You can do so as follows: +```ts +Configure.set('app configure item', 'my value'); +``` + **NOTE**: Changes made here do not persist between restarts of your app. ## Checking whether an item exists +To check whether an item exists, just run the following: +```ts +const exists = Configure.check('app configure item'); +``` + ## Consume a Configure item +Consuming a Configure item will return the item and then remove it. +```ts +const myConst = Configure.consume('app configure item', 'default value'); +``` + ## Delete a Configure item +Deleting a configure item will remove it from the Configure. + +```ts +Configure.delete('app configure item'); +``` + +**NOTE**: Changes made here do not persist between restarts of your app. + ## Dump all Configure items +Sometimes it is useful to know all the items that are currently in the Configure. +In this case, you can simply dump all the contents: +```ts +console.log(Configure.dump()); +``` + +```ts +Map(3) { + "debug" => false, + "error_log" => "/path/to/logs/error.log", + "app configuration key" => "app configuration value" +} +``` + **NOTE**: This should only be done for debugging purposes as it may leak sensitive information! ## Clear or reset all Configure items @@ -93,3 +131,10 @@ Map(2) { "error_log" => "/path/to/logs/error.log" } ``` + +However, the default state is coded into Chomp itself and is *not* your app's defaults. +If instead, you want to use your app's defaults, you must first clear/reset then force a load: +```ts +Configure.clear(); // Or reset depending on your needs +await Configure.load(true); // Force the configure to reload +``` From d6eddf83d7a2fd881fae898a7e2c552254f13f3d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 2 Feb 2024 13:13:05 +0100 Subject: [PATCH 202/379] Add PR template --- .github/pull_request_template.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..13acebbb --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,27 @@ +### What changes are being made + + +- [INSERT CHANGE HERE] + +### What is the context? + + +I made this PR because ... + +### Some checks you should make + + +- [ ] You have no left-over console logs. +- [ ] You have no left-over debuggers. +- [ ] You have no left-over other pieces or code. +- [ ] You have kept the documentation in-sync with the code as much as possible. +- [ ] You have nothing to add after taking a break and coming in cold. + +### Some checks we should make + + +- [ ] Changes have no left-over console logs. +- [ ] Changes have no left-over debuggers. +- [ ] Changes have no left-over other pieces or code. +- [ ] Changes have kept the documentation in-sync with the code as much as possible. +- [ ] Changes still look good after taking a break and coming in cold. From e48ec010663ef44c1d777f52e9702648c337895a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 3 Feb 2024 00:05:32 +0100 Subject: [PATCH 203/379] Document CheckSource --- docs/utility/check-source.md | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/docs/utility/check-source.md b/docs/utility/check-source.md index af14f17a..f0fcfe14 100644 --- a/docs/utility/check-source.md +++ b/docs/utility/check-source.md @@ -1 +1,59 @@ # CheckSource + +CheckSource allows you to run the Deno file checking before hand. +This is useful for helping speed up deployments and reboots as you can now do all the checks in the pipeline rather than while starting the container. + +## Getting Started + +First, import the module as part of Chomp's core: +```ts +import * from "https://deno.land/x/chomp/mod.ts"; +``` + +Or if you want a more minimal setup: +```ts +import { CheckSource } from "https://deno.land/x/chomp/mod.ts"; +``` + +Then add the following code to your check script: +```ts +const checker = new CheckSource('./src'); +await checker.run(); +``` + +Then run the script. +A common way of doing it would be to add a file `check.ts` and running that: + +```ts +// check.ts +import { CheckSource } from "https://deno.land/x/chomp/mod.ts"; + +const checker = new CheckSource('./src'); +await checker.run(); +``` + +``` +>>> deno run --allow-read check.ts +[2024/02/02 23:55:27] INFO > Getting all files in directory "./src"... +[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/controller"... +[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/controller/component"... +[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/events"... +[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/templates"... +[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/templates/anidb"... +[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/templates/database"... +[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/templates/status"... +[2024/02/02 23:55:27] INFO > Checking "15" files... +[2024/02/02 23:55:27] INFO > Finished checking files! +``` + +## Excluding files or directories + +In some cases, you may have additional files or directories mixed into your directory that you may not want to be checked, such as your handlebars templates. +These files and directories can be specified to be ignored very simply by specifying them in the constructor: + +```ts +const checker = new CheckSource('./src', { + directories: ['my-dir'], + files: ['my-file.txt'] +}); +``` From 77a2e223aecd3714c89076a7fc52e7ebff60cb18 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 2 Apr 2024 13:54:40 +0200 Subject: [PATCH 204/379] Update documentation a bit --- communication/couchdb.ts | 1 + docs/communication/couchdb.md | 84 +++++++++++++++++++++++++++++++++++ docs/utility/README.md | 1 + 3 files changed, 86 insertions(+) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index a4ba2e4a..c3b4e515 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -117,6 +117,7 @@ export class CouchDB { /** * Delete a document from the database. + * TODO: Automatically find revision. * * @param id * @param revision diff --git a/docs/communication/couchdb.md b/docs/communication/couchdb.md index af4cf69b..c779e7d9 100644 --- a/docs/communication/couchdb.md +++ b/docs/communication/couchdb.md @@ -25,12 +25,96 @@ db.password = 'lamepassword'; ## Getting a document +Getting a document from CouchDB can be done very easily: +```ts +const existing = await db.get('my-key'); +``` + +If you want to then check whether a document was found, just check the `status`: +```ts +if(existing.status === 404) { + // Handle non-existing document +} +``` + ## Inserting a document +If you want to insert a document, it can be done in the following way: +```ts +const resp = await db.insert({ + '_id': 'my-key', + 'data': 'my-data', +}); +``` + +You can then check whether the operation was a success: +```ts +if(resp.status !== 201) { + // Handle insert error +} +``` + +**NOTE**: Despite this example showing an object called "`data`" in the document, this value is chosen "arbitrarily". +**NOTE**: Any document passed to the method will be attempted to insert "as-is". +A more convenient "[`upsert`](#upserting-a-document)" method is available. + ## Updating a document +If you want to update a document, it can be done in the following way: +```ts +const resp = await db.update('my-key', 'my-new-data'); +``` + +You can then check whether the operation was a success: +```ts +if(resp.status !== 201) { + // Handle insert error +} +``` + +**NOTE**: Despite this example using a "`my-new-data`" string, any data can be passed here and be updated "as-is". +**NOTE**: This example does not check whether a document exists to be updated. +A more convenient "[`upsert`](#upserting-a-document)" method is available. + ## Upserting a document +Upserting combines `insert` and `update` in a single function. +It'll automatically check whether a document exists, inserting if it doesn't and updating if it does. + +```ts +const resp = await db.upsert(`my-key`, 'my-data'); +``` + +You can then check whether the operation was a success: +```ts +if(resp.status !== 201) { + // Handle upsert error +} +``` + +**NOTE**: Despite this example using a "`my-data`" string, any data can be passed here and be updated "as-is". + ## Deleting a document +Once a document is no longer needed, one may want to delete it. +To do so, you can use the `delete` method: +```ts +const existing = await db.get('my-key'); +if(existing.status === 404) return; +const resp = await db.delete('my-key', existing.data['_rev']); +``` + +You can then check whether the operation was a success: +```ts +if(resp.status !== 200) { + // Handle deletion error +} +``` + +**NOTE**: Currently, the revision must be passed manually to the `delete` method. + ## Making a raw query + +Sometimes, you may want to take a bit more control, for this, you can use the `raw` method. +However, we do not provide any examples of it as it simply can do too much, this block is simply there to inform you the option is there. +If you want to use it, you probably are smarter than this library but feel free to have a look by yourself. diff --git a/docs/utility/README.md b/docs/utility/README.md index 0b58bca8..e378f07c 100644 --- a/docs/utility/README.md +++ b/docs/utility/README.md @@ -1 +1,2 @@ # Utility +General utilities that we didn't see fit under a category just yet. From 24b7d9c80978710bad3cd102764bfe659e9fa2a7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 4 Apr 2024 23:56:29 +0200 Subject: [PATCH 205/379] Add method to Text to allow for escaping HTML entities --- tests/util/text.ts | 19 +++++++++++++++++++ utility/text.ts | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/util/text.ts diff --git a/tests/util/text.ts b/tests/util/text.ts new file mode 100644 index 00000000..5a0968a4 --- /dev/null +++ b/tests/util/text.ts @@ -0,0 +1,19 @@ +import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; +import { Text } from "../../utility/text.ts"; + +Deno.test("Text Test", async (t) => { + Deno.test("htmlentities", async (t) => { + // Test all supported entities + assertEquals(Text.htmlentities('&'), '&'); + assertEquals(Text.htmlentities('<'), '<'); + assertEquals(Text.htmlentities('>'), '>'); + assertEquals(Text.htmlentities('\''), '''); + assertEquals(Text.htmlentities('"'), '"'); + + // Test regular characters + assertEquals(Text.htmlentities('1'), '1'); + assertEquals(Text.htmlentities('2'), '2'); + assertEquals(Text.htmlentities('a'), 'a'); + assertEquals(Text.htmlentities('b'), 'b'); + }); +}); diff --git a/utility/text.ts b/utility/text.ts index a6cacc33..9b983d0f 100644 --- a/utility/text.ts +++ b/utility/text.ts @@ -22,4 +22,21 @@ export class Text { return tokens; } + + /** + * Replace special characters with their HTML entities. + * TODO: Add support for diacritical marks. + * + * @param str + * @returns string + */ + public static htmlentities(str: string): string { + return str.replace(/[&<>'"]/g, (tag: string) => ({ + '&': '&', + '<': '<', + '>': '>', + "'": ''', + '"': '"', + }[tag] ?? tag)) + } } From 47232bcdd9519bca2613b30e66f06e40fbc5d558 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 26 May 2024 05:12:19 +0200 Subject: [PATCH 206/379] Fix bug with source checks never running properly --- utility/check-source.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/check-source.ts b/utility/check-source.ts index 53bf1f7f..652459fa 100644 --- a/utility/check-source.ts +++ b/utility/check-source.ts @@ -54,7 +54,7 @@ export class CheckSource { Logger.debug(`Skipping excluded file "${path}/${entry.name}"...`); continue; } - if(new File(`${path}/${entry.name}`).ext() !== '.ts') { + if(new File(`${path}/${entry.name}`).ext() !== 'ts') { Logger.debug(`Skipping non-ts file...`); continue; } From 82389a3fdf78a40f71eb3c7ce07433786e9dec55 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 17 Jun 2024 20:23:14 +0200 Subject: [PATCH 207/379] Allow writing bulk to InfluxDB --- communication/influxdb.ts | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/communication/influxdb.ts b/communication/influxdb.ts index abe905f7..f30bc5e1 100644 --- a/communication/influxdb.ts +++ b/communication/influxdb.ts @@ -33,14 +33,21 @@ export class InfluxDB { } /** - * Write our datapoint to InfluxDB - * - * @param point + * Write our datapoint(s) to InfluxDB + * + * @param data */ - public async write(point: Point): Promise { - // Convert point to Line Protocol entry - const line = point.toLine(this._api.precision); - + public async write(data: Point|Point[]): Promise { + // Convert point(s) to Line Protocol entry + let points = ''; + if(Array.isArray(data)) { + for await(const point of data) { + points += `${point.toLine(this._api.precision)}\n`; + } + } else { + points = data.toLine(this._api.precision); + } + // Write line to InfluxDB try { const resp = await fetch(this._api.url, { @@ -49,11 +56,11 @@ export class InfluxDB { 'Content-Type': 'text/plain', }, method: 'POST', - body: line, + body: points, }); return resp.ok; } catch(e) { - Logger.error(`Could not write point to InfluxDB`, e.stack); + Logger.error(`Could not write point(s) to InfluxDB`, e.stack); return false; } } From 4519c7c135ad95318e5111597819db094f0f12ba Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 17 Aug 2024 16:19:55 +0200 Subject: [PATCH 208/379] Allow multiple paths to be checked in one go --- utility/check-source.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/utility/check-source.ts b/utility/check-source.ts index 652459fa..5c0a71b9 100644 --- a/utility/check-source.ts +++ b/utility/check-source.ts @@ -11,13 +11,15 @@ export class CheckSource { private errors = 0; constructor( - private readonly path: string, + private readonly paths: string[], private readonly exclusions: ExclusionConfig = { directories: [], files: [] } ) {} public async run(): Promise { - // Get list of files - await this.getFiles(this.path); + // Get all files in all paths + for(const path of this.paths) { + await this.getFiles(path); + } // Check all files found Logger.info(`Checking "${this.files.length}" files...`); @@ -28,7 +30,7 @@ export class CheckSource { Logger.info(`Finished checking files with ${this.errors} errors!\r\nPlease check the logs above for more information.`); Deno.exit(1); } - Logger.info(`Finished checking files!`); + Logger.info(`Finished checking files without errors!`); Deno.exit(0); } From e572c03fcbf2f770fccbf53600a785b76abd1658 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 17 Aug 2024 22:33:04 +0200 Subject: [PATCH 209/379] Disallow setting null and undefined --- core/configure.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/core/configure.ts b/core/configure.ts index 254cfa21..c421d252 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -49,23 +49,23 @@ export class Configure { } /** - * Obtain the value of a key in the configure + * Obtain the value of a key in the configure. + * * * @param key Key to look for * @param defaultValue Default value to return when no result was found - * @returns any + * @returns any|null */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - public static get(key: string, defaultValue: any = null): any { - // Check if the key exists. - // If not: return the default value - // Else: return the value in the Configure + public static get(key: string, defaultValue: any = null): any|null { + // Return null if we do not have the key if(!Configure.config.has(key)) return defaultValue; return Configure.config.get(key); } /** * Set a configure item + * It is not possible to store null values * * @param key * @param value @@ -73,6 +73,7 @@ export class Configure { */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static set(key: string, value: any): void { + if(value === null || typeof value === 'undefined') return; Configure.config.set(key, value); } From adeaf7eb1cf517cf3a6078022e507fae2698a712 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 1 Sep 2024 18:58:49 +0200 Subject: [PATCH 210/379] Standardize error codes --- error/error-codes.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 error/error-codes.ts diff --git a/error/error-codes.ts b/error/error-codes.ts new file mode 100644 index 00000000..c117c86b --- /dev/null +++ b/error/error-codes.ts @@ -0,0 +1,29 @@ +export enum ErrorCodes { + // Standard Errors + UNKNOWN_ERROR = 0x0000000, + DEPRECATED_FUNCTION_CALL = 0x000001, + + // Data errors + // TODO: Implement + + // Filesystem Errors + FILE_READ_GENERIC = 0x210, + FILE_READ_NOT_FOUND = 0x211, + FILE_READ_NO_PERM = 0x212, + FILE_WRITE_GENERIC = 0x220, + FILE_WRITE_NOT_FOUND = 0x221, + FILE_WRITE_NO_PERM = 0x222, + + // Upstream Errors + UPSTREAM_HTTP_BAD_REQUEST = 0x300400, + UPSTREAM_HTTP__UNAUTHORIZED = 0x300401, + UPSTREAM_HTTP_FORBIDDEN = 0x300403, + UPSTREAM_HTTP_NOT_FOUND = 0x300404, + UPSTREAM_HTTP_METHOD_NOT_ALLOWED = 0x300405, + UPSTREAM_HTTP_REQUEST_TIMEOUT = 0x300408, + UPSTREAM_HTTP_TOO_MANY_REQUESTS = 0x300429, + UPSTREAM_HTTP_INTERNAL_SERVER_ERROR = 0x300500, + UPSTREAM_HTTP_BAD_GATEWAY = 0x300502, + UPSTREAM_HTTP_SERVICE_UNAVAILABLE = 0x300503, + UPSTREAM_HTTP_GATEWAY_TIMEOUT = 0x300504, +} From f0019bdaf32b1f6420621de2c79c3be5c0a93db2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 3 Sep 2024 21:20:41 +0200 Subject: [PATCH 211/379] Move CouchDB docs to file instead --- communication/couchdb.ts | 117 ++++++++++++++++++++++++++++++++- docs/communication/couchdb.md | 120 ---------------------------------- 2 files changed, 114 insertions(+), 123 deletions(-) delete mode 100644 docs/communication/couchdb.md diff --git a/communication/couchdb.ts b/communication/couchdb.ts index c3b4e515..fe788d33 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -21,6 +21,26 @@ interface CouchOverrides { export class CouchDB { private auth = ''; + /** + * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB( + * 'http://localhost:5984', + * 'my_database', + * { + * username: 'couchuser', + * password: 'lamepassword' + * } + * ); + * ``` + * + * @param host + * @param database + * @param auth + */ public constructor( private readonly host: string = 'http://localhost:5984', private readonly database: string, @@ -33,9 +53,17 @@ export class CouchDB { * Update the username for this instance. * This does *not* update the username on the server. * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(); + * couchdb.username = 'couchuser'; + * ``` + * * @param username */ - public set username(username: string): void { + public set username(username: string) { // Get the password from the data const password = atob(this.auth).split(':')[1]; @@ -47,9 +75,17 @@ export class CouchDB { * Update the password for this instance. * This does *not* update the password on the server. * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(); + * couchdb.password = 'lamepassword'; + * ``` + * * @param password */ - public set password(password: string): void { + public set password(password: string) { // Get the password from the data const username = atob(this.auth).split(':')[0]; @@ -60,6 +96,18 @@ export class CouchDB { /** * Get a document from the database. * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(...); + * const existing = await couchdb.get('my-key'); + * + * if(existing.status === 404) { + * // Handle non-existing document + * } + * ``` + * * @param id */ public async get(id: string): Promise { @@ -69,6 +117,24 @@ export class CouchDB { /** * Insert a document into the database. * + * Any document passed to the method will be attempted to insert "as-is". + * The more convenient "{@linkcode CouchDB.upsert()}" method should be used most of the time. + * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(...); + * const resp = await couchdb.insert({ + * '_id': 'my-key', + * 'data': 'my-data', + * }); + * + * if(resp.status !== 201) { + * // Handle insert error + * } + * ``` + * * @param data */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used @@ -78,7 +144,21 @@ export class CouchDB { /** * Update a document in the database. - * This is only useful if you know the latest revision, otherwise see the "upsert" method instead. + * + * This is only useful if you know the latest revision. + * The more convenient "{@linkcode CouchDB.upsert()}" should be used most of the time. + * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(...); + * const resp = await couchdb.update(`my-key`, '1-abcdef', 'my-data'); + * + * if(resp.status !== 201) { + * // Handle update error + * } + * ``` * * @param id * @param revision @@ -98,6 +178,18 @@ export class CouchDB { * This method will automatically check if an existing document exists and try to update it. * If no document exists, it will be created instead. * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(...); + * const resp = await couchdb.upsert(`my-key`, 'my-data'); + * + * if(resp.status !== 201) { + * // Handle upsert error + * } + * ``` + * * @param id * @param data */ @@ -119,6 +211,20 @@ export class CouchDB { * Delete a document from the database. * TODO: Automatically find revision. * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(...); + * const existing = await couchdb.get('my-key'); + * if(existing.status === 404) return; + * const resp = await couchdb.delete('my-key', existing.data['_rev']); + * + * if(resp.status !== 200) { + * // Handle deletion error + * } + * ``` + * * @param id * @param revision */ @@ -130,6 +236,11 @@ export class CouchDB { * Main request handler. * This method is used for most of our other methods as well. * + * @example + * ```ts + * // TODO: Write example + * ``` + * * @param endpoint * @param body * @param overrides diff --git a/docs/communication/couchdb.md b/docs/communication/couchdb.md deleted file mode 100644 index c779e7d9..00000000 --- a/docs/communication/couchdb.md +++ /dev/null @@ -1,120 +0,0 @@ -# CouchDB - -Facilitates communication with [CouchDB](https://couchdb.apache.org/). - -### Getting Started - -First import the module as follows: -```ts -import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; -``` - -Next, we must create an instance of the class that we can use to talk to CouchDB. - -```ts -// Option 1 (preferred) -const db = new CouchDB('http://localhost:5984', 'my_database', { username: 'couchuser', password: 'lamepassword'}); -``` - -```ts -// Option 2 -const db = new CouchDB('http://localhost:5984', 'my_database'); -db.username = 'couchuser'; -db.password = 'lamepassword'; -``` - -## Getting a document - -Getting a document from CouchDB can be done very easily: -```ts -const existing = await db.get('my-key'); -``` - -If you want to then check whether a document was found, just check the `status`: -```ts -if(existing.status === 404) { - // Handle non-existing document -} -``` - -## Inserting a document - -If you want to insert a document, it can be done in the following way: -```ts -const resp = await db.insert({ - '_id': 'my-key', - 'data': 'my-data', -}); -``` - -You can then check whether the operation was a success: -```ts -if(resp.status !== 201) { - // Handle insert error -} -``` - -**NOTE**: Despite this example showing an object called "`data`" in the document, this value is chosen "arbitrarily". -**NOTE**: Any document passed to the method will be attempted to insert "as-is". -A more convenient "[`upsert`](#upserting-a-document)" method is available. - -## Updating a document - -If you want to update a document, it can be done in the following way: -```ts -const resp = await db.update('my-key', 'my-new-data'); -``` - -You can then check whether the operation was a success: -```ts -if(resp.status !== 201) { - // Handle insert error -} -``` - -**NOTE**: Despite this example using a "`my-new-data`" string, any data can be passed here and be updated "as-is". -**NOTE**: This example does not check whether a document exists to be updated. -A more convenient "[`upsert`](#upserting-a-document)" method is available. - -## Upserting a document - -Upserting combines `insert` and `update` in a single function. -It'll automatically check whether a document exists, inserting if it doesn't and updating if it does. - -```ts -const resp = await db.upsert(`my-key`, 'my-data'); -``` - -You can then check whether the operation was a success: -```ts -if(resp.status !== 201) { - // Handle upsert error -} -``` - -**NOTE**: Despite this example using a "`my-data`" string, any data can be passed here and be updated "as-is". - -## Deleting a document - -Once a document is no longer needed, one may want to delete it. -To do so, you can use the `delete` method: -```ts -const existing = await db.get('my-key'); -if(existing.status === 404) return; -const resp = await db.delete('my-key', existing.data['_rev']); -``` - -You can then check whether the operation was a success: -```ts -if(resp.status !== 200) { - // Handle deletion error -} -``` - -**NOTE**: Currently, the revision must be passed manually to the `delete` method. - -## Making a raw query - -Sometimes, you may want to take a bit more control, for this, you can use the `raw` method. -However, we do not provide any examples of it as it simply can do too much, this block is simply there to inform you the option is there. -If you want to use it, you probably are smarter than this library but feel free to have a look by yourself. From d6841d0ff918294e67dfa79e3941ad8b7a2bbefd Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 8 Sep 2024 16:50:08 +0200 Subject: [PATCH 212/379] Allow executing a view design --- communication/couchdb.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index fe788d33..10d96d1f 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -232,6 +232,28 @@ export class CouchDB { return await this.raw(`${id}?rev=${revision}`, null, { method: 'DELETE' }); } + /** + * Execute a view design + * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(...); + * const resp = await couchdb.viewDesign('my-design', 'my-view', 'my-partition'); + * if(resp.status !== 200) { + * // Handle view error + * } + * ``` + * + * @param design + * @param view + * @param partition + */ + public async viewDesign(design: string, view: string, partition: string): Promise{ + return await this.raw(`_partition/${partition}/_design/${design}/_view/${view}`); + } + /** * Main request handler. * This method is used for most of our other methods as well. From 576d93f440f2a39eeab61037d7c80a562c22756e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 11:44:37 +0200 Subject: [PATCH 213/379] Move Logger to Core --- communication/influxdb.ts | 2 +- communication/loki.ts | 2 +- communication/nut.ts | 2 +- communication/redis.ts | 2 +- core/cache.ts | 2 +- core/configure.ts | 2 +- filesystem/folder.ts | 2 +- mod.ts | 2 +- queue/queue.ts | 2 +- utility/check-source.ts | 2 +- webserver/controller/controller.ts | 2 +- webserver/routing/router.ts | 2 +- webserver/webserver.ts | 2 +- websocket/authenticator.ts | 2 +- websocket/events.ts | 2 +- websocket/websocket.ts | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/communication/influxdb.ts b/communication/influxdb.ts index f30bc5e1..62c050fb 100644 --- a/communication/influxdb.ts +++ b/communication/influxdb.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; export enum Precision { s, diff --git a/communication/loki.ts b/communication/loki.ts index 211f3762..7b3b19c3 100644 --- a/communication/loki.ts +++ b/communication/loki.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; export interface LokiStream { // deno-lint-ignore no-explicit-any -- TODO diff --git a/communication/nut.ts b/communication/nut.ts index b4528430..cda66296 100644 --- a/communication/nut.ts +++ b/communication/nut.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; export class NutState { public static readonly WAITING = 0; diff --git a/communication/redis.ts b/communication/redis.ts index 5c996c4a..d5f63e80 100644 --- a/communication/redis.ts +++ b/communication/redis.ts @@ -1,5 +1,5 @@ import { connect as redisConnect, Redis as RedisConn } from "https://deno.land/x/redis@v0.25.2/mod.ts" -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; export class Redis { private static connection: RedisConn|null = null; diff --git a/core/cache.ts b/core/cache.ts index d7b7639d..b8720026 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -1,5 +1,5 @@ import { T as TimeString } from "../utility/time-string.ts"; -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; import { Cron } from "../utility/cron.ts"; interface CacheItem { diff --git a/core/configure.ts b/core/configure.ts index c421d252..4c3980c9 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; // deno-lint-ignore no-explicit-any -- Arbitrary data may be used const defaults = new Map([ diff --git a/filesystem/folder.ts b/filesystem/folder.ts index 541030b2..65c0865c 100644 --- a/filesystem/folder.ts +++ b/filesystem/folder.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; export class Folder { public constructor( diff --git a/mod.ts b/mod.ts index 9c92e2ea..ce462bb9 100644 --- a/mod.ts +++ b/mod.ts @@ -4,7 +4,7 @@ */ export { Cache } from "./core/cache.ts"; export { Configure } from "./core/configure.ts"; -export { Logger } from "./logging/logger.ts"; +export { Logger } from "./core/logger.ts"; export { File } from "./filesystem/file.ts"; export { Folder } from "./filesystem/folder.ts"; export { CheckSource } from "./utility/check-source.ts"; diff --git a/queue/queue.ts b/queue/queue.ts index 3e87526b..8c9eb894 100644 --- a/queue/queue.ts +++ b/queue/queue.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; interface QueueItem { weight?: number; diff --git a/utility/check-source.ts b/utility/check-source.ts index 5c0a71b9..2bea890a 100644 --- a/utility/check-source.ts +++ b/utility/check-source.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; import { File } from "../filesystem/file.ts"; export interface ExclusionConfig { diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index a6bfb2d7..b203104b 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -1,4 +1,4 @@ -import { Logger } from "../../logging/logger.ts"; +import { Logger } from "../../core/logger.ts"; import { Inflector } from "../../utility/inflector.ts"; import { Handlebars } from "../renderers/handlebars.ts"; import { ResponseBuilder } from "../http/response-builder.ts"; diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 2d309c3c..557ba80a 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -2,7 +2,7 @@ import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts" import { readAll } from "https://deno.land/std@0.213.0/io/read_all.ts"; import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../utility/inflector.ts"; -import { Logger } from "../../logging/logger.ts"; +import { Logger } from "../../core/logger.ts"; import {QueryParameters, Request as ChompRequest, RequestParameters} from "../http/request.ts"; import { StatusCodes } from "../http/status-codes.ts"; import { Route as ChompRoute } from "./route.ts"; diff --git a/webserver/webserver.ts b/webserver/webserver.ts index 2b868d52..d9461db7 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; import { Router } from "./routing/router.ts"; import { StatusCodes } from "./http/status-codes.ts"; diff --git a/websocket/authenticator.ts b/websocket/authenticator.ts index e92fbc1f..b0b8d9e3 100644 --- a/websocket/authenticator.ts +++ b/websocket/authenticator.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; import { Configure } from "../core/configure.ts"; export class Authenticator { diff --git a/websocket/events.ts b/websocket/events.ts index 2f283ddd..034bd3d0 100644 --- a/websocket/events.ts +++ b/websocket/events.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; interface IEvent { name: string; diff --git a/websocket/websocket.ts b/websocket/websocket.ts index 23176041..e55fa421 100644 --- a/websocket/websocket.ts +++ b/websocket/websocket.ts @@ -1,5 +1,5 @@ import { WebSocketServer, WebSocketAcceptedClient } from "https://deno.land/x/websocket@v0.1.3/mod.ts"; -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; import { Events } from "./events.ts"; import { Authenticator } from "./authenticator.ts"; import { Configure } from "../core/configure.ts"; From 0d248eb00217049dd50aac3e0e60d6ca0d7b6a1e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 11:46:40 +0200 Subject: [PATCH 214/379] Move old docs while I'm rewriting them --- {docs => docs-old}/communication/README.md | 0 {docs => docs-old}/communication/druid.md | 0 {docs => docs-old}/communication/graphql.md | 0 {docs => docs-old}/communication/influxdb.md | 0 {docs => docs-old}/communication/loki.md | 0 {docs => docs-old}/communication/ntfy.md | 0 {docs => docs-old}/communication/nut.md | 0 {docs => docs-old}/communication/rcon.md | 0 {docs => docs-old}/communication/redis.md | 0 {docs => docs-old}/core/README.md | 0 {docs => docs-old}/core/cache.md | 0 {docs => docs-old}/core/configure.md | 0 {docs => docs-old}/error/README.md | 0 {docs => docs-old}/error/raise.md | 0 {docs => docs-old}/filesystem/README.md | 0 {docs => docs-old}/filesystem/file.md | 0 {docs => docs-old}/filesystem/folder.md | 0 {docs => docs-old}/logging/README.md | 0 {docs => docs-old}/logging/logger.md | 0 {docs => docs-old}/queue/README.md | 0 {docs => docs-old}/security/README.md | 0 {docs => docs-old}/utility/README.md | 0 {docs => docs-old}/utility/check-source.md | 0 {docs => docs-old}/utility/time-string.md | 0 {docs => docs-old}/webserver/README.md | 0 {docs => docs-old}/websocket/README.md | 0 docs/discord/README.md | 1 - 27 files changed, 1 deletion(-) rename {docs => docs-old}/communication/README.md (100%) rename {docs => docs-old}/communication/druid.md (100%) rename {docs => docs-old}/communication/graphql.md (100%) rename {docs => docs-old}/communication/influxdb.md (100%) rename {docs => docs-old}/communication/loki.md (100%) rename {docs => docs-old}/communication/ntfy.md (100%) rename {docs => docs-old}/communication/nut.md (100%) rename {docs => docs-old}/communication/rcon.md (100%) rename {docs => docs-old}/communication/redis.md (100%) rename {docs => docs-old}/core/README.md (100%) rename {docs => docs-old}/core/cache.md (100%) rename {docs => docs-old}/core/configure.md (100%) rename {docs => docs-old}/error/README.md (100%) rename {docs => docs-old}/error/raise.md (100%) rename {docs => docs-old}/filesystem/README.md (100%) rename {docs => docs-old}/filesystem/file.md (100%) rename {docs => docs-old}/filesystem/folder.md (100%) rename {docs => docs-old}/logging/README.md (100%) rename {docs => docs-old}/logging/logger.md (100%) rename {docs => docs-old}/queue/README.md (100%) rename {docs => docs-old}/security/README.md (100%) rename {docs => docs-old}/utility/README.md (100%) rename {docs => docs-old}/utility/check-source.md (100%) rename {docs => docs-old}/utility/time-string.md (100%) rename {docs => docs-old}/webserver/README.md (100%) rename {docs => docs-old}/websocket/README.md (100%) delete mode 100644 docs/discord/README.md diff --git a/docs/communication/README.md b/docs-old/communication/README.md similarity index 100% rename from docs/communication/README.md rename to docs-old/communication/README.md diff --git a/docs/communication/druid.md b/docs-old/communication/druid.md similarity index 100% rename from docs/communication/druid.md rename to docs-old/communication/druid.md diff --git a/docs/communication/graphql.md b/docs-old/communication/graphql.md similarity index 100% rename from docs/communication/graphql.md rename to docs-old/communication/graphql.md diff --git a/docs/communication/influxdb.md b/docs-old/communication/influxdb.md similarity index 100% rename from docs/communication/influxdb.md rename to docs-old/communication/influxdb.md diff --git a/docs/communication/loki.md b/docs-old/communication/loki.md similarity index 100% rename from docs/communication/loki.md rename to docs-old/communication/loki.md diff --git a/docs/communication/ntfy.md b/docs-old/communication/ntfy.md similarity index 100% rename from docs/communication/ntfy.md rename to docs-old/communication/ntfy.md diff --git a/docs/communication/nut.md b/docs-old/communication/nut.md similarity index 100% rename from docs/communication/nut.md rename to docs-old/communication/nut.md diff --git a/docs/communication/rcon.md b/docs-old/communication/rcon.md similarity index 100% rename from docs/communication/rcon.md rename to docs-old/communication/rcon.md diff --git a/docs/communication/redis.md b/docs-old/communication/redis.md similarity index 100% rename from docs/communication/redis.md rename to docs-old/communication/redis.md diff --git a/docs/core/README.md b/docs-old/core/README.md similarity index 100% rename from docs/core/README.md rename to docs-old/core/README.md diff --git a/docs/core/cache.md b/docs-old/core/cache.md similarity index 100% rename from docs/core/cache.md rename to docs-old/core/cache.md diff --git a/docs/core/configure.md b/docs-old/core/configure.md similarity index 100% rename from docs/core/configure.md rename to docs-old/core/configure.md diff --git a/docs/error/README.md b/docs-old/error/README.md similarity index 100% rename from docs/error/README.md rename to docs-old/error/README.md diff --git a/docs/error/raise.md b/docs-old/error/raise.md similarity index 100% rename from docs/error/raise.md rename to docs-old/error/raise.md diff --git a/docs/filesystem/README.md b/docs-old/filesystem/README.md similarity index 100% rename from docs/filesystem/README.md rename to docs-old/filesystem/README.md diff --git a/docs/filesystem/file.md b/docs-old/filesystem/file.md similarity index 100% rename from docs/filesystem/file.md rename to docs-old/filesystem/file.md diff --git a/docs/filesystem/folder.md b/docs-old/filesystem/folder.md similarity index 100% rename from docs/filesystem/folder.md rename to docs-old/filesystem/folder.md diff --git a/docs/logging/README.md b/docs-old/logging/README.md similarity index 100% rename from docs/logging/README.md rename to docs-old/logging/README.md diff --git a/docs/logging/logger.md b/docs-old/logging/logger.md similarity index 100% rename from docs/logging/logger.md rename to docs-old/logging/logger.md diff --git a/docs/queue/README.md b/docs-old/queue/README.md similarity index 100% rename from docs/queue/README.md rename to docs-old/queue/README.md diff --git a/docs/security/README.md b/docs-old/security/README.md similarity index 100% rename from docs/security/README.md rename to docs-old/security/README.md diff --git a/docs/utility/README.md b/docs-old/utility/README.md similarity index 100% rename from docs/utility/README.md rename to docs-old/utility/README.md diff --git a/docs/utility/check-source.md b/docs-old/utility/check-source.md similarity index 100% rename from docs/utility/check-source.md rename to docs-old/utility/check-source.md diff --git a/docs/utility/time-string.md b/docs-old/utility/time-string.md similarity index 100% rename from docs/utility/time-string.md rename to docs-old/utility/time-string.md diff --git a/docs/webserver/README.md b/docs-old/webserver/README.md similarity index 100% rename from docs/webserver/README.md rename to docs-old/webserver/README.md diff --git a/docs/websocket/README.md b/docs-old/websocket/README.md similarity index 100% rename from docs/websocket/README.md rename to docs-old/websocket/README.md diff --git a/docs/discord/README.md b/docs/discord/README.md deleted file mode 100644 index 8b32d7a1..00000000 --- a/docs/discord/README.md +++ /dev/null @@ -1 +0,0 @@ -# Discord From 1b7623d222a7df0746fc25605628b7f860b49a31 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 11:47:28 +0200 Subject: [PATCH 215/379] Document Random --- docs-old/security/README.md | 1 - security/random.ts | 62 ++++++++++++++++++++++++++++++++----- webserver/routing/router.ts | 2 +- 3 files changed, 56 insertions(+), 9 deletions(-) delete mode 100644 docs-old/security/README.md diff --git a/docs-old/security/README.md b/docs-old/security/README.md deleted file mode 100644 index 8dbb2f9b..00000000 --- a/docs-old/security/README.md +++ /dev/null @@ -1 +0,0 @@ -# Security diff --git a/security/random.ts b/security/random.ts index 2032fb1d..bdadab3e 100644 --- a/security/random.ts +++ b/security/random.ts @@ -1,7 +1,15 @@ export class Random { /** * Generate random bytes. - * These bytes are generated using the Web Crypto API, this cryptographically secure. + * These bytes are generated using the Web Crypto API, this is cryptographically secure. + * + * @example Basic Usage + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * + * // Generates 16 random bytes + * const bytes = Random.bytes(16); + * ``` * * @param length Amount of bytes to be generated * @returns Uint8Array @@ -14,7 +22,15 @@ export class Random { /** * Generate a random string. - * These strings are generated using the Web Crypto API, this cryptographically secure. + * These strings are generated using the Web Crypto API, this is cryptographically secure. + * + * @example Basic Usage + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * + * // Generates a string with 16 characters + * const str = await Random.string(16); + * ``` * * @param length Length of the string to be generated * @returns Promise @@ -26,11 +42,27 @@ export class Random { /** * Inclusively generate a random integer between min and max. - * If you want to use decimals, please use Random.float() instead. - * + * If you want to use decimals, please use "{@linkcode Random.float()}" instead. + * * By default, these integers are **NOT** cryptographically secure (for performance reasons). * Set the "secure" argument to "true" if you are using this for cryptographic purposes! - * + * + * @example Basic Usage + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * + * // Generate a random integer between 0 and 10 + * const num = await Random.integer(0, 10); + * ``` + * + * @example Cryptographically secure + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * + * // Generate a secure random integer between 0 and 10 + * const num = await Random.integer(0, 10, true); + * ``` + * * @param min Minimum allowable integer * @param max Maximum allowable integer * @param secure Using this for cryptographic purposes? @@ -39,7 +71,7 @@ export class Random { // Strip decimals min = Math.ceil(min); max = Math.floor(max); - + // Generate a number using Random.float and floor that return Math.floor(Random.float(min, max, secure)); } @@ -47,10 +79,26 @@ export class Random { /** * Inclusively generate a random float between min and max. * If you do not want to use decimals, please use Random.integer() instead. - * + * * By default, these floats are **NOT** cryptographically secure (for performance reasons). * Set the "secure" argument to "true" if you are using this for cryptographic purposes! * + * @example Basic Usage + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * + * // Generate a random float between 0 and 1 + * const num = await Random.float(0, 1); + * ``` + * + * @example Cryptographically secure + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * + * // Generate a secure random float between 0 and 1 + * const num = await Random.float(0, 1, true); + * ``` + * * @param min Minimum allowable float * @param max Maximum allowable float * @param secure Using this for cryptographic purposes? diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 557ba80a..b87c81f7 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -34,7 +34,7 @@ export class Router { .replace("http://", "") .replace("https://", ""); if(host !== null) path = path.replace(host, ""); - + // Ignore query parameters path = path.split("?", 1)[0]; From 59bbfc87f5e74f9c6fe9ffeebdc9995b8c1abeea Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 11:53:02 +0200 Subject: [PATCH 216/379] Copy-pasta too stronk --- security/random.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/security/random.ts b/security/random.ts index bdadab3e..7ea747c6 100644 --- a/security/random.ts +++ b/security/random.ts @@ -5,7 +5,7 @@ export class Random { * * @example Basic Usage * ```ts - * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * import { Random } from "https://deno.land/x/chomp/security/random.ts"; * * // Generates 16 random bytes * const bytes = Random.bytes(16); @@ -26,7 +26,7 @@ export class Random { * * @example Basic Usage * ```ts - * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * import { Random } from "https://deno.land/x/chomp/security/random.ts"; * * // Generates a string with 16 characters * const str = await Random.string(16); @@ -49,7 +49,7 @@ export class Random { * * @example Basic Usage * ```ts - * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * import { Random } from "https://deno.land/x/chomp/security/random.ts"; * * // Generate a random integer between 0 and 10 * const num = await Random.integer(0, 10); @@ -57,7 +57,7 @@ export class Random { * * @example Cryptographically secure * ```ts - * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * import { Random } from "https://deno.land/x/chomp/security/random.ts"; * * // Generate a secure random integer between 0 and 10 * const num = await Random.integer(0, 10, true); @@ -85,7 +85,7 @@ export class Random { * * @example Basic Usage * ```ts - * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * import { Random } from "https://deno.land/x/chomp/security/random.ts"; * * // Generate a random float between 0 and 1 * const num = await Random.float(0, 1); @@ -93,7 +93,7 @@ export class Random { * * @example Cryptographically secure * ```ts - * import { CouchDB } from "https://deno.land/x/chomp/security/random.ts"; + * import { Random } from "https://deno.land/x/chomp/security/random.ts"; * * // Generate a secure random float between 0 and 1 * const num = await Random.float(0, 1, true); From 954f7f7ceefea4d29c4ac2c944bd8c0d977c0c51 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 13:07:15 +0200 Subject: [PATCH 217/379] Migrate all existing docs --- README.md | 4 +- common.ts | 8 + communication/influxdb.ts | 28 +- core/cache.ts | 80 +- core/configure.ts | 96 +- {logging => core}/logger.ts | 6 +- core/mod.ts | 3 + deno.lock | 417 +++ discord/discord.ts | 253 -- discord/event/dispatcher.ts | 133 - discord/event/event.ts | 3 - discord/interaction/builder.ts | 164 - discord/interaction/dispatcher.ts | 160 - discord/interaction/interaction.ts | 40 - discord/mod.ts | 25 - discord/util/find-channel-by-name.ts | 27 - discord/util/find-role-by-name.ts | 41 - discord/util/snowflake-to-date.ts | 12 - docs-old/communication/README.md | 3 - docs-old/communication/druid.md | 1 - docs-old/communication/graphql.md | 7 - docs-old/communication/influxdb.md | 1 - docs-old/communication/loki.md | 1 - docs-old/communication/ntfy.md | 1 - docs-old/communication/nut.md | 1 - docs-old/communication/rcon.md | 1 - docs-old/communication/redis.md | 1 - docs-old/core/README.md | 1 - docs-old/core/cache.md | 87 - docs-old/core/configure.md | 140 - docs-old/error/README.md | 1 - docs-old/error/raise.md | 65 - docs-old/filesystem/README.md | 1 - docs-old/filesystem/file.md | 1 - docs-old/filesystem/folder.md | 1 - docs-old/logging/README.md | 0 docs-old/logging/logger.md | 1 - docs-old/queue/README.md | 1 - docs-old/utility/README.md | 2 - docs-old/utility/check-source.md | 59 - docs-old/utility/time-string.md | 1 - docs-old/webserver/README.md | 4 - docs-old/websocket/README.md | 1 - docs/all_symbols.html | 348 ++ docs/fuse.js | 11 + docs/index.html | 65 + docs/page.css | 1 + docs/script.js | 33 + docs/search.js | 168 + docs/search_index.js | 3 + docs/styles.css | 1 + docs/~/Algorithms.html | 1228 ++++++ docs/~/Authenticator.client.html | 253 ++ docs/~/Authenticator.html | 157 + docs/~/Authenticator.prototype.html | 1 + docs/~/Cache._items.html | 156 + docs/~/Cache.consume.html | 372 ++ docs/~/Cache.dump.html | 243 ++ docs/~/Cache.exists.html | 319 ++ docs/~/Cache.expired.html | 318 ++ docs/~/Cache.get.html | 412 ++ docs/~/Cache.html | 602 +++ docs/~/Cache.prototype.html | 1 + docs/~/Cache.remove.html | 318 ++ docs/~/Cache.set.html | 427 +++ docs/~/Cache.sweep.html | 243 ++ docs/~/CheckSource.html | 679 ++++ docs/~/CheckSource.prototype.addFile.html | 252 ++ docs/~/CheckSource.prototype.checkFiles.html | 176 + docs/~/CheckSource.prototype.errors.html | 156 + docs/~/CheckSource.prototype.files.html | 156 + docs/~/CheckSource.prototype.getFiles.html | 253 ++ docs/~/CheckSource.prototype.html | 1 + docs/~/CheckSource.prototype.run.html | 175 + docs/~/Configure.check.html | 321 ++ docs/~/Configure.clear.html | 246 ++ docs/~/Configure.config.html | 156 + docs/~/Configure.consume.html | 415 +++ docs/~/Configure.delete.html | 321 ++ docs/~/Configure.dump.html | 245 ++ docs/~/Configure.get.html | 418 +++ docs/~/Configure.hasLoaded.html | 156 + docs/~/Configure.html | 705 ++++ docs/~/Configure.load.html | 321 ++ docs/~/Configure.prototype.html | 1 + docs/~/Configure.reset.html | 245 ++ docs/~/Configure.set.html | 373 ++ docs/~/Controller._componentDir.html | 156 + docs/~/Controller._templateDir.html | 156 + docs/~/Controller.html | 813 ++++ docs/~/Controller.prototype._response.html | 156 + docs/~/Controller.prototype._vars.html | 156 + docs/~/Controller.prototype.getRequest.html | 176 + docs/~/Controller.prototype.getResponse.html | 176 + docs/~/Controller.prototype.html | 1 + docs/~/Controller.prototype.initialize.html | 177 + .../~/Controller.prototype.loadComponent.html | 251 ++ docs/~/Controller.prototype.render.html | 178 + docs/~/Controller.prototype.set.html | 303 ++ docs/~/Controller.prototype.type.html | 255 ++ docs/~/CouchDB.html | 739 ++++ docs/~/CouchDB.prototype.auth.html | 156 + docs/~/CouchDB.prototype.delete.html | 384 ++ docs/~/CouchDB.prototype.get.html | 328 ++ docs/~/CouchDB.prototype.html | 1 + docs/~/CouchDB.prototype.insert.html | 336 ++ docs/~/CouchDB.prototype.password.html | 321 ++ docs/~/CouchDB.prototype.raw.html | 419 +++ docs/~/CouchDB.prototype.update.html | 432 +++ docs/~/CouchDB.prototype.upsert.html | 381 ++ docs/~/CouchDB.prototype.username.html | 321 ++ docs/~/CouchDB.prototype.viewDesign.html | 428 +++ docs/~/Cron.Cron.html | 81 + docs/~/Cron.html | 379 ++ docs/~/DEFAULT_OPTS.html | 158 + docs/~/Druid.html | 415 +++ docs/~/Druid.prototype.create.html | 177 + docs/~/Druid.prototype.getSpec.html | 175 + docs/~/Druid.prototype.html | 1 + docs/~/Druid.prototype.setSpec.html | 251 ++ docs/~/Druid.prototype.spec.html | 156 + docs/~/ErrorCodes.html | 1074 ++++++ docs/~/Events.add.html | 251 ++ docs/~/Events.dispatch.html | 252 ++ docs/~/Events.getEvents.html | 124 + docs/~/Events.getHandler.html | 200 + docs/~/Events.handlers.html | 156 + docs/~/Events.html | 438 +++ docs/~/Events.list.html | 156 + docs/~/Events.prototype.html | 1 + docs/~/ExclusionConfig.directories.html | 156 + docs/~/ExclusionConfig.files.html | 156 + docs/~/ExclusionConfig.html | 209 ++ docs/~/File.html | 488 +++ docs/~/File.prototype.create.html | 175 + docs/~/File.prototype.delete.html | 175 + docs/~/File.prototype.exists.html | 175 + docs/~/File.prototype.ext.html | 175 + docs/~/File.prototype.html | 1 + docs/~/File.prototype.readFile.html | 124 + docs/~/File.prototype.readTextFile.html | 124 + docs/~/Folder.html | 286 ++ docs/~/Folder.prototype.create.html | 254 ++ docs/~/Folder.prototype.exists.html | 176 + docs/~/Folder.prototype.html | 1 + docs/~/GraphQL.html | 466 +++ docs/~/GraphQL.prototype._query.html | 156 + docs/~/GraphQL.prototype._variables.html | 79 + docs/~/GraphQL.prototype.addVariable.html | 304 ++ docs/~/GraphQL.prototype.execute.html | 124 + docs/~/GraphQL.prototype.html | 1 + docs/~/GraphQL.prototype.setQuery.html | 253 ++ docs/~/Hash.html | 363 ++ docs/~/Hash.prototype.digest.html | 289 ++ docs/~/Hash.prototype.hex.html | 195 + docs/~/Hash.prototype.html | 1 + docs/~/Hash.prototype.result.html | 156 + docs/~/INSECURE_ALGORITHMS.html | 157 + docs/~/Inflector.camelize.html | 305 ++ docs/~/Inflector.html | 367 ++ docs/~/Inflector.humanize.html | 305 ++ docs/~/Inflector.lcfirst.html | 252 ++ docs/~/Inflector.pascalize.html | 305 ++ docs/~/Inflector.prototype.html | 1 + docs/~/Inflector.ucfirst.html | 252 ++ docs/~/InfluxDB.html | 362 ++ docs/~/InfluxDB.prototype._api.html | 156 + docs/~/InfluxDB.prototype.html | 1 + docs/~/InfluxDB.prototype.setApi.html | 354 ++ docs/~/InfluxDB.prototype.write.html | 252 ++ docs/~/Logger._handlers.html | 156 + docs/~/Logger.debug.html | 254 ++ docs/~/Logger.error.html | 307 ++ docs/~/Logger.html | 499 +++ docs/~/Logger.info.html | 253 ++ docs/~/Logger.prototype.html | 1 + docs/~/Logger.setHandler.html | 305 ++ docs/~/Logger.time.html | 180 + docs/~/Logger.warning.html | 253 ++ docs/~/Loki.html | 234 ++ docs/~/Loki.prototype.html | 1 + docs/~/Loki.prototype.send.html | 252 ++ docs/~/Ntfy.html | 234 ++ docs/~/Ntfy.prototype.html | 1 + docs/~/Ntfy.prototype.send.html | 252 ++ docs/~/Nut.html | 1083 ++++++ docs/~/Nut.prototype.UPSList.html | 124 + docs/~/Nut.prototype._status.html | 156 + docs/~/Nut.prototype.callback.html | 156 + docs/~/Nut.prototype.client.html | 156 + docs/~/Nut.prototype.close.html | 175 + docs/~/Nut.prototype.connect.html | 175 + docs/~/Nut.prototype.dataBuf.html | 156 + docs/~/Nut.prototype.getCharge.html | 251 ++ docs/~/Nut.prototype.getLoad.html | 251 ++ docs/~/Nut.prototype.getPowerLimit.html | 251 ++ docs/~/Nut.prototype.getRuntime.html | 251 ++ docs/~/Nut.prototype.getStatus.html | 251 ++ docs/~/Nut.prototype.host.html | 156 + docs/~/Nut.prototype.html | 1 + docs/~/Nut.prototype.onReceive.html | 175 + docs/~/Nut.prototype.port.html | 156 + docs/~/Nut.prototype.send.html | 302 ++ docs/~/Nut.prototype.status.html | 175 + docs/~/PASSWORD_DEFAULT.html | 81 + docs/~/Password.doHash.html | 404 ++ docs/~/Password.hash.html | 357 ++ docs/~/Password.html | 260 ++ docs/~/Password.prototype.html | 1 + docs/~/Password.verify.html | 305 ++ docs/~/PasswordOptions.allowInsecure.html | 156 + docs/~/PasswordOptions.cost.html | 156 + docs/~/PasswordOptions.html | 210 ++ docs/~/QueryParameters.html | 128 + docs/~/Queue.html | 735 ++++ docs/~/Queue.prototype.add.html | 253 ++ docs/~/Queue.prototype.clear.html | 177 + docs/~/Queue.prototype.contains.html | 253 ++ docs/~/Queue.prototype.count.html | 177 + docs/~/Queue.prototype.dump.html | 177 + docs/~/Queue.prototype.html | 1 + docs/~/Queue.prototype.isEmpty.html | 177 + docs/~/Queue.prototype.items.html | 156 + docs/~/Queue.prototype.next.html | 178 + docs/~/Queue.prototype.peek.html | 178 + docs/~/Queue.prototype.scheduler.html | 156 + docs/~/RCON.html | 445 +++ docs/~/RCON.prototype.close.html | 177 + docs/~/RCON.prototype.conn.html | 156 + docs/~/RCON.prototype.connect.html | 356 ++ docs/~/RCON.prototype.html | 1 + docs/~/RCON.prototype.recv.html | 177 + docs/~/RCON.prototype.send.html | 305 ++ docs/~/RCON.prototype.sendSync.html | 307 ++ docs/~/Random.bytes.html | 323 ++ docs/~/Random.float.html | 474 +++ docs/~/Random.html | 321 ++ docs/~/Random.integer.html | 474 +++ docs/~/Random.prototype.html | 1 + docs/~/Random.string.html | 323 ++ docs/~/Redis.connect.html | 306 ++ docs/~/Redis.connection.html | 156 + docs/~/Redis.getConnection.html | 177 + docs/~/Redis.html | 286 ++ docs/~/Redis.prototype.html | 1 + docs/~/Request.html | 743 ++++ docs/~/Request.prototype.getAuth.html | 175 + docs/~/Request.prototype.getBody.html | 175 + docs/~/Request.prototype.getHeaders.html | 175 + docs/~/Request.prototype.getIp.html | 175 + docs/~/Request.prototype.getMethod.html | 175 + docs/~/Request.prototype.getParam.html | 251 ++ docs/~/Request.prototype.getParams.html | 175 + docs/~/Request.prototype.getQuery.html | 251 ++ docs/~/Request.prototype.getQueryParams.html | 175 + docs/~/Request.prototype.getRoute.html | 175 + docs/~/Request.prototype.getUrl.html | 175 + docs/~/Request.prototype.html | 1 + docs/~/RequestParameters.html | 128 + docs/~/Router._controllerDir.html | 156 + docs/~/Router.add.html | 254 ++ docs/~/Router.execute.html | 304 ++ docs/~/Router.getAuth.html | 253 ++ docs/~/Router.getBody.html | 253 ++ docs/~/Router.getParams.html | 304 ++ docs/~/Router.getQuery.html | 253 ++ docs/~/Router.getRoutes.html | 124 + docs/~/Router.html | 651 ++++ docs/~/Router.prototype.html | 1 + docs/~/Router.route.html | 201 + docs/~/Router.routes.html | 156 + docs/~/StatusCodes.html | 3318 +++++++++++++++++ docs/~/Text.html | 262 ++ docs/~/Text.htmlentities.html | 254 ++ docs/~/Text.prototype.html | 1 + docs/~/Text.tokenize.html | 304 ++ docs/~/Text.uuid.html | 176 + docs/~/Time.html | 983 +++++ docs/~/Time.prototype.add.html | 200 + docs/~/Time.prototype.addDay.html | 201 + docs/~/Time.prototype.addWeek.html | 201 + docs/~/Time.prototype.format.html | 200 + docs/~/Time.prototype.getTime.html | 124 + docs/~/Time.prototype.hours.html | 124 + docs/~/Time.prototype.html | 1 + docs/~/Time.prototype.midnight.html | 124 + docs/~/Time.prototype.milliseconds.html | 124 + docs/~/Time.prototype.minutes.html | 124 + docs/~/Time.prototype.month.html | 124 + docs/~/Time.prototype.monthDay.html | 124 + docs/~/Time.prototype.seconds.html | 124 + docs/~/Time.prototype.time.html | 79 + docs/~/Time.prototype.weekDay.html | 124 + docs/~/Time.prototype.year.html | 124 + docs/~/TimeString.html | 304 ++ docs/~/TimeStringSeconds.html | 304 ++ docs/~/ViewVariable.html | 128 + docs/~/Webserver.html | 362 ++ docs/~/Webserver.prototype.html | 1 + docs/~/Webserver.prototype.serve.html | 251 ++ docs/~/Webserver.prototype.server.html | 156 + docs/~/Webserver.prototype.start.html | 175 + docs/~/Websocket.html | 571 +++ docs/~/Websocket.prototype.authenticate.html | 156 + docs/~/Websocket.prototype.broadcast.html | 302 ++ docs/~/Websocket.prototype.handleEvent.html | 252 ++ docs/~/Websocket.prototype.html | 1 + docs/~/Websocket.prototype.onMessage.html | 251 ++ docs/~/Websocket.prototype.port.html | 156 + docs/~/Websocket.prototype.server.html | 156 + docs/~/Websocket.prototype.start.html | 175 + docs/~/raise.html | 547 +++ error/raise.ts | 40 +- filesystem/folder.ts | 2 +- mod.ts | 65 +- security/hash.ts | 32 + security/password.ts | 13 +- utility/check-source.ts | 29 + utility/time-string.ts | 6 +- utility/time.ts | 4 +- webserver/controller/controller.ts | 24 +- webserver/routing/router.ts | 18 +- webserver/webserver.ts | 2 +- websocket/websocket.ts | 2 +- 324 files changed, 66588 insertions(+), 1311 deletions(-) create mode 100644 common.ts rename {logging => core}/logger.ts (98%) create mode 100644 core/mod.ts create mode 100644 deno.lock delete mode 100644 discord/discord.ts delete mode 100644 discord/event/dispatcher.ts delete mode 100644 discord/event/event.ts delete mode 100644 discord/interaction/builder.ts delete mode 100644 discord/interaction/dispatcher.ts delete mode 100644 discord/interaction/interaction.ts delete mode 100644 discord/mod.ts delete mode 100644 discord/util/find-channel-by-name.ts delete mode 100644 discord/util/find-role-by-name.ts delete mode 100644 discord/util/snowflake-to-date.ts delete mode 100644 docs-old/communication/README.md delete mode 100644 docs-old/communication/druid.md delete mode 100644 docs-old/communication/graphql.md delete mode 100644 docs-old/communication/influxdb.md delete mode 100644 docs-old/communication/loki.md delete mode 100644 docs-old/communication/ntfy.md delete mode 100644 docs-old/communication/nut.md delete mode 100644 docs-old/communication/rcon.md delete mode 100644 docs-old/communication/redis.md delete mode 100644 docs-old/core/README.md delete mode 100644 docs-old/core/cache.md delete mode 100644 docs-old/core/configure.md delete mode 100644 docs-old/error/README.md delete mode 100644 docs-old/error/raise.md delete mode 100644 docs-old/filesystem/README.md delete mode 100644 docs-old/filesystem/file.md delete mode 100644 docs-old/filesystem/folder.md delete mode 100644 docs-old/logging/README.md delete mode 100644 docs-old/logging/logger.md delete mode 100644 docs-old/queue/README.md delete mode 100644 docs-old/utility/README.md delete mode 100644 docs-old/utility/check-source.md delete mode 100644 docs-old/utility/time-string.md delete mode 100644 docs-old/webserver/README.md delete mode 100644 docs-old/websocket/README.md create mode 100644 docs/all_symbols.html create mode 100644 docs/fuse.js create mode 100644 docs/index.html create mode 100644 docs/page.css create mode 100644 docs/script.js create mode 100644 docs/search.js create mode 100644 docs/search_index.js create mode 100644 docs/styles.css create mode 100644 docs/~/Algorithms.html create mode 100644 docs/~/Authenticator.client.html create mode 100644 docs/~/Authenticator.html create mode 100644 docs/~/Authenticator.prototype.html create mode 100644 docs/~/Cache._items.html create mode 100644 docs/~/Cache.consume.html create mode 100644 docs/~/Cache.dump.html create mode 100644 docs/~/Cache.exists.html create mode 100644 docs/~/Cache.expired.html create mode 100644 docs/~/Cache.get.html create mode 100644 docs/~/Cache.html create mode 100644 docs/~/Cache.prototype.html create mode 100644 docs/~/Cache.remove.html create mode 100644 docs/~/Cache.set.html create mode 100644 docs/~/Cache.sweep.html create mode 100644 docs/~/CheckSource.html create mode 100644 docs/~/CheckSource.prototype.addFile.html create mode 100644 docs/~/CheckSource.prototype.checkFiles.html create mode 100644 docs/~/CheckSource.prototype.errors.html create mode 100644 docs/~/CheckSource.prototype.files.html create mode 100644 docs/~/CheckSource.prototype.getFiles.html create mode 100644 docs/~/CheckSource.prototype.html create mode 100644 docs/~/CheckSource.prototype.run.html create mode 100644 docs/~/Configure.check.html create mode 100644 docs/~/Configure.clear.html create mode 100644 docs/~/Configure.config.html create mode 100644 docs/~/Configure.consume.html create mode 100644 docs/~/Configure.delete.html create mode 100644 docs/~/Configure.dump.html create mode 100644 docs/~/Configure.get.html create mode 100644 docs/~/Configure.hasLoaded.html create mode 100644 docs/~/Configure.html create mode 100644 docs/~/Configure.load.html create mode 100644 docs/~/Configure.prototype.html create mode 100644 docs/~/Configure.reset.html create mode 100644 docs/~/Configure.set.html create mode 100644 docs/~/Controller._componentDir.html create mode 100644 docs/~/Controller._templateDir.html create mode 100644 docs/~/Controller.html create mode 100644 docs/~/Controller.prototype._response.html create mode 100644 docs/~/Controller.prototype._vars.html create mode 100644 docs/~/Controller.prototype.getRequest.html create mode 100644 docs/~/Controller.prototype.getResponse.html create mode 100644 docs/~/Controller.prototype.html create mode 100644 docs/~/Controller.prototype.initialize.html create mode 100644 docs/~/Controller.prototype.loadComponent.html create mode 100644 docs/~/Controller.prototype.render.html create mode 100644 docs/~/Controller.prototype.set.html create mode 100644 docs/~/Controller.prototype.type.html create mode 100644 docs/~/CouchDB.html create mode 100644 docs/~/CouchDB.prototype.auth.html create mode 100644 docs/~/CouchDB.prototype.delete.html create mode 100644 docs/~/CouchDB.prototype.get.html create mode 100644 docs/~/CouchDB.prototype.html create mode 100644 docs/~/CouchDB.prototype.insert.html create mode 100644 docs/~/CouchDB.prototype.password.html create mode 100644 docs/~/CouchDB.prototype.raw.html create mode 100644 docs/~/CouchDB.prototype.update.html create mode 100644 docs/~/CouchDB.prototype.upsert.html create mode 100644 docs/~/CouchDB.prototype.username.html create mode 100644 docs/~/CouchDB.prototype.viewDesign.html create mode 100644 docs/~/Cron.Cron.html create mode 100644 docs/~/Cron.html create mode 100644 docs/~/DEFAULT_OPTS.html create mode 100644 docs/~/Druid.html create mode 100644 docs/~/Druid.prototype.create.html create mode 100644 docs/~/Druid.prototype.getSpec.html create mode 100644 docs/~/Druid.prototype.html create mode 100644 docs/~/Druid.prototype.setSpec.html create mode 100644 docs/~/Druid.prototype.spec.html create mode 100644 docs/~/ErrorCodes.html create mode 100644 docs/~/Events.add.html create mode 100644 docs/~/Events.dispatch.html create mode 100644 docs/~/Events.getEvents.html create mode 100644 docs/~/Events.getHandler.html create mode 100644 docs/~/Events.handlers.html create mode 100644 docs/~/Events.html create mode 100644 docs/~/Events.list.html create mode 100644 docs/~/Events.prototype.html create mode 100644 docs/~/ExclusionConfig.directories.html create mode 100644 docs/~/ExclusionConfig.files.html create mode 100644 docs/~/ExclusionConfig.html create mode 100644 docs/~/File.html create mode 100644 docs/~/File.prototype.create.html create mode 100644 docs/~/File.prototype.delete.html create mode 100644 docs/~/File.prototype.exists.html create mode 100644 docs/~/File.prototype.ext.html create mode 100644 docs/~/File.prototype.html create mode 100644 docs/~/File.prototype.readFile.html create mode 100644 docs/~/File.prototype.readTextFile.html create mode 100644 docs/~/Folder.html create mode 100644 docs/~/Folder.prototype.create.html create mode 100644 docs/~/Folder.prototype.exists.html create mode 100644 docs/~/Folder.prototype.html create mode 100644 docs/~/GraphQL.html create mode 100644 docs/~/GraphQL.prototype._query.html create mode 100644 docs/~/GraphQL.prototype._variables.html create mode 100644 docs/~/GraphQL.prototype.addVariable.html create mode 100644 docs/~/GraphQL.prototype.execute.html create mode 100644 docs/~/GraphQL.prototype.html create mode 100644 docs/~/GraphQL.prototype.setQuery.html create mode 100644 docs/~/Hash.html create mode 100644 docs/~/Hash.prototype.digest.html create mode 100644 docs/~/Hash.prototype.hex.html create mode 100644 docs/~/Hash.prototype.html create mode 100644 docs/~/Hash.prototype.result.html create mode 100644 docs/~/INSECURE_ALGORITHMS.html create mode 100644 docs/~/Inflector.camelize.html create mode 100644 docs/~/Inflector.html create mode 100644 docs/~/Inflector.humanize.html create mode 100644 docs/~/Inflector.lcfirst.html create mode 100644 docs/~/Inflector.pascalize.html create mode 100644 docs/~/Inflector.prototype.html create mode 100644 docs/~/Inflector.ucfirst.html create mode 100644 docs/~/InfluxDB.html create mode 100644 docs/~/InfluxDB.prototype._api.html create mode 100644 docs/~/InfluxDB.prototype.html create mode 100644 docs/~/InfluxDB.prototype.setApi.html create mode 100644 docs/~/InfluxDB.prototype.write.html create mode 100644 docs/~/Logger._handlers.html create mode 100644 docs/~/Logger.debug.html create mode 100644 docs/~/Logger.error.html create mode 100644 docs/~/Logger.html create mode 100644 docs/~/Logger.info.html create mode 100644 docs/~/Logger.prototype.html create mode 100644 docs/~/Logger.setHandler.html create mode 100644 docs/~/Logger.time.html create mode 100644 docs/~/Logger.warning.html create mode 100644 docs/~/Loki.html create mode 100644 docs/~/Loki.prototype.html create mode 100644 docs/~/Loki.prototype.send.html create mode 100644 docs/~/Ntfy.html create mode 100644 docs/~/Ntfy.prototype.html create mode 100644 docs/~/Ntfy.prototype.send.html create mode 100644 docs/~/Nut.html create mode 100644 docs/~/Nut.prototype.UPSList.html create mode 100644 docs/~/Nut.prototype._status.html create mode 100644 docs/~/Nut.prototype.callback.html create mode 100644 docs/~/Nut.prototype.client.html create mode 100644 docs/~/Nut.prototype.close.html create mode 100644 docs/~/Nut.prototype.connect.html create mode 100644 docs/~/Nut.prototype.dataBuf.html create mode 100644 docs/~/Nut.prototype.getCharge.html create mode 100644 docs/~/Nut.prototype.getLoad.html create mode 100644 docs/~/Nut.prototype.getPowerLimit.html create mode 100644 docs/~/Nut.prototype.getRuntime.html create mode 100644 docs/~/Nut.prototype.getStatus.html create mode 100644 docs/~/Nut.prototype.host.html create mode 100644 docs/~/Nut.prototype.html create mode 100644 docs/~/Nut.prototype.onReceive.html create mode 100644 docs/~/Nut.prototype.port.html create mode 100644 docs/~/Nut.prototype.send.html create mode 100644 docs/~/Nut.prototype.status.html create mode 100644 docs/~/PASSWORD_DEFAULT.html create mode 100644 docs/~/Password.doHash.html create mode 100644 docs/~/Password.hash.html create mode 100644 docs/~/Password.html create mode 100644 docs/~/Password.prototype.html create mode 100644 docs/~/Password.verify.html create mode 100644 docs/~/PasswordOptions.allowInsecure.html create mode 100644 docs/~/PasswordOptions.cost.html create mode 100644 docs/~/PasswordOptions.html create mode 100644 docs/~/QueryParameters.html create mode 100644 docs/~/Queue.html create mode 100644 docs/~/Queue.prototype.add.html create mode 100644 docs/~/Queue.prototype.clear.html create mode 100644 docs/~/Queue.prototype.contains.html create mode 100644 docs/~/Queue.prototype.count.html create mode 100644 docs/~/Queue.prototype.dump.html create mode 100644 docs/~/Queue.prototype.html create mode 100644 docs/~/Queue.prototype.isEmpty.html create mode 100644 docs/~/Queue.prototype.items.html create mode 100644 docs/~/Queue.prototype.next.html create mode 100644 docs/~/Queue.prototype.peek.html create mode 100644 docs/~/Queue.prototype.scheduler.html create mode 100644 docs/~/RCON.html create mode 100644 docs/~/RCON.prototype.close.html create mode 100644 docs/~/RCON.prototype.conn.html create mode 100644 docs/~/RCON.prototype.connect.html create mode 100644 docs/~/RCON.prototype.html create mode 100644 docs/~/RCON.prototype.recv.html create mode 100644 docs/~/RCON.prototype.send.html create mode 100644 docs/~/RCON.prototype.sendSync.html create mode 100644 docs/~/Random.bytes.html create mode 100644 docs/~/Random.float.html create mode 100644 docs/~/Random.html create mode 100644 docs/~/Random.integer.html create mode 100644 docs/~/Random.prototype.html create mode 100644 docs/~/Random.string.html create mode 100644 docs/~/Redis.connect.html create mode 100644 docs/~/Redis.connection.html create mode 100644 docs/~/Redis.getConnection.html create mode 100644 docs/~/Redis.html create mode 100644 docs/~/Redis.prototype.html create mode 100644 docs/~/Request.html create mode 100644 docs/~/Request.prototype.getAuth.html create mode 100644 docs/~/Request.prototype.getBody.html create mode 100644 docs/~/Request.prototype.getHeaders.html create mode 100644 docs/~/Request.prototype.getIp.html create mode 100644 docs/~/Request.prototype.getMethod.html create mode 100644 docs/~/Request.prototype.getParam.html create mode 100644 docs/~/Request.prototype.getParams.html create mode 100644 docs/~/Request.prototype.getQuery.html create mode 100644 docs/~/Request.prototype.getQueryParams.html create mode 100644 docs/~/Request.prototype.getRoute.html create mode 100644 docs/~/Request.prototype.getUrl.html create mode 100644 docs/~/Request.prototype.html create mode 100644 docs/~/RequestParameters.html create mode 100644 docs/~/Router._controllerDir.html create mode 100644 docs/~/Router.add.html create mode 100644 docs/~/Router.execute.html create mode 100644 docs/~/Router.getAuth.html create mode 100644 docs/~/Router.getBody.html create mode 100644 docs/~/Router.getParams.html create mode 100644 docs/~/Router.getQuery.html create mode 100644 docs/~/Router.getRoutes.html create mode 100644 docs/~/Router.html create mode 100644 docs/~/Router.prototype.html create mode 100644 docs/~/Router.route.html create mode 100644 docs/~/Router.routes.html create mode 100644 docs/~/StatusCodes.html create mode 100644 docs/~/Text.html create mode 100644 docs/~/Text.htmlentities.html create mode 100644 docs/~/Text.prototype.html create mode 100644 docs/~/Text.tokenize.html create mode 100644 docs/~/Text.uuid.html create mode 100644 docs/~/Time.html create mode 100644 docs/~/Time.prototype.add.html create mode 100644 docs/~/Time.prototype.addDay.html create mode 100644 docs/~/Time.prototype.addWeek.html create mode 100644 docs/~/Time.prototype.format.html create mode 100644 docs/~/Time.prototype.getTime.html create mode 100644 docs/~/Time.prototype.hours.html create mode 100644 docs/~/Time.prototype.html create mode 100644 docs/~/Time.prototype.midnight.html create mode 100644 docs/~/Time.prototype.milliseconds.html create mode 100644 docs/~/Time.prototype.minutes.html create mode 100644 docs/~/Time.prototype.month.html create mode 100644 docs/~/Time.prototype.monthDay.html create mode 100644 docs/~/Time.prototype.seconds.html create mode 100644 docs/~/Time.prototype.time.html create mode 100644 docs/~/Time.prototype.weekDay.html create mode 100644 docs/~/Time.prototype.year.html create mode 100644 docs/~/TimeString.html create mode 100644 docs/~/TimeStringSeconds.html create mode 100644 docs/~/ViewVariable.html create mode 100644 docs/~/Webserver.html create mode 100644 docs/~/Webserver.prototype.html create mode 100644 docs/~/Webserver.prototype.serve.html create mode 100644 docs/~/Webserver.prototype.server.html create mode 100644 docs/~/Webserver.prototype.start.html create mode 100644 docs/~/Websocket.html create mode 100644 docs/~/Websocket.prototype.authenticate.html create mode 100644 docs/~/Websocket.prototype.broadcast.html create mode 100644 docs/~/Websocket.prototype.handleEvent.html create mode 100644 docs/~/Websocket.prototype.html create mode 100644 docs/~/Websocket.prototype.onMessage.html create mode 100644 docs/~/Websocket.prototype.port.html create mode 100644 docs/~/Websocket.prototype.server.html create mode 100644 docs/~/Websocket.prototype.start.html create mode 100644 docs/~/raise.html diff --git a/README.md b/README.md index d6a523f0..dcdda08d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Should work just fine but comes with no warranties whatsoever. Chomp is structured in such a way that you can import just what you need for your app. A good start would be to import the most common things you might use: ```ts -import * from "https://deno.land/x/chomp/mod.ts"; +import * from "https://deno.land/x/chomp/common.ts"; ``` This includes (list might not always be up-to-date): @@ -35,6 +35,8 @@ import * from "https://deno.land/x/chomp/websocket/mod.ts"; Additionally, you can explore the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what more Chomp is capable off! +**NOTE**: While you can import `https://deno.land/x/chomp/mod.ts`, we advice against this as it'll load the entire codebase, including stuff you may not actually be using. + ## Versioning Versions adhere to the following versioning system of `x.y.z` where: diff --git a/common.ts b/common.ts new file mode 100644 index 00000000..28199d7e --- /dev/null +++ b/common.ts @@ -0,0 +1,8 @@ +/** + * These are just the exports you'll most commonly use. + * You can view the "docs"-directory to see what else there is! + */ +export { Cache, Configure, Logger } from "./core/mod.ts"; +export { File } from "./filesystem/file.ts"; +export { Folder } from "./filesystem/folder.ts"; +export { CheckSource } from "./utility/check-source.ts"; diff --git a/communication/influxdb.ts b/communication/influxdb.ts index 62c050fb..706e6d98 100644 --- a/communication/influxdb.ts +++ b/communication/influxdb.ts @@ -15,20 +15,20 @@ interface Api { export class InfluxDB { private _api: Api; - + public constructor( private readonly url: string, private readonly token: string, ) { } - + public setApi(org: string, bucket: string, precision: Precision = Precision.us): this { this._api = { url: `${this.url}/api/v2/write?org=${org}&bucket=${bucket}&precision=${Precision[precision]}`, auth: `Token ${this.token}`, precision: precision, }; - + return this; } @@ -70,7 +70,7 @@ export class Point { private _tags: Map = new Map(); private _fields: Map = new Map(); private _timestamp: Date|number = 0; - + public constructor( private readonly measurement: string, ) { @@ -78,7 +78,7 @@ export class Point { /** * Add a tag to our point - * + * * @param key * @param value */ @@ -89,7 +89,7 @@ export class Point { /** * Add a field to our point - * + * * @param key * @param value */ @@ -102,36 +102,36 @@ export class Point { * Set our timestamp for the point. * Can be either a date or a number. * In the case that this is a number, it must be in the correct precision units. - * + * * @param ts */ public setTimestamp(ts: Date|number): this { this._timestamp = ts; return this; } - + public toLine(precision: Precision = Precision.us): string { // Start off with a blank string let line = ''; - + // Set the measurement line += this.measurement; - + // Add all tags for(const [key, value] of this._tags.entries()) { line += `,${key}=${value}`; } - + // Add separator before fieldset line += ' '; - + // Add all fields const entries = []; for(const [key, value] of this._fields.entries()) { entries.push(`${key}=${value}`); } line += entries.join(','); - + // Add timestamp let ts = 0; if(this._timestamp instanceof Date) { @@ -153,7 +153,7 @@ export class Point { ts = this._timestamp; } line += ` ${ts}`; - + // Return our final line return line; } diff --git a/core/cache.ts b/core/cache.ts index b8720026..8bd5baac 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -13,6 +13,17 @@ export class Cache { /** * Add an item to the cache. * + * @example Basic Usage + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * + * Cache.set('I expire in 1 minute', 'foo'); + * Cache.set('I expire in 10 minutes', 'bar', '+10 minutes'); + * Cache.set('I never expire', 'baz', null); + * ``` + * + * **NOTE**: Expiry times use {@linkcode TimeString} formats. + * * @param key * @param value * @param expiry Can be set to null for never expiring items @@ -20,7 +31,7 @@ export class Cache { public static set(key: string, value: unknown, expiry: string|null = '+1 minute'): void { let expiresAt = null; if(expiry) expiresAt = new Date(new Date().getTime() + TimeString`${expiry}`) - + Cache._items.set(key, { data: value, expires: expiresAt, @@ -30,6 +41,20 @@ export class Cache { /** * Get an item from the cache * + * @example Basic Usage + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * + * Cache.get('cache item name'); + * ``` + * + * @example Getting expired items + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * + * const item = Cache.get('cache item name', true); + * ``` + * * @param key * @param optimistic Whether to serve expired items from the cache */ @@ -48,6 +73,13 @@ export class Cache { * Check whether an item exists in the cache. * This does *not* check whether the item has expired or not. * + * @example Basic Usage + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * + * const doesExist = Cache.exists('cache item name'); + * ``` + * * @param key */ public static exists(key: string): boolean { @@ -57,6 +89,13 @@ export class Cache { /** * Check whether an item has expired * + * @example Basic Usage + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * + * const hasExpired = Cache.expired('cache item name'); + * ``` + * * @param key */ public static expired(key: string): boolean { @@ -71,17 +110,24 @@ export class Cache { /** * Consume an item from the cache. * Differs from "Cache.get()" in that it removes the item afterwards. - * + * + * @example Basic Usage + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * + * const item = Cache.consume('cache item name'); + * ``` + * * @param key * @param optimistic Whether to serve expired items from the cache */ public static consume(key: string, optimistic = false): unknown|null { // Copy item from cache const data = Cache.get(key, optimistic); - + // Remove item from cache Cache.remove(key); - + // Return the item return data; } @@ -89,6 +135,13 @@ export class Cache { /** * Remove an item from the cache * + * @example Basic Usage + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * + * Cache.remove('cache item name'); + * ``` + * * @param key */ public static remove(key: string): void { @@ -98,6 +151,13 @@ export class Cache { /** * Dumps the raw cache contents. * Should only be used for debugging purposes. + * + * @example Basic Usage + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * + * console.log(Cache.dump()); + * ``` */ public static dump(): Map { return Cache._items; @@ -105,6 +165,14 @@ export class Cache { /** * Scan the cache and clean up expired items while keeping optimistic caching in tact. + * There shouldn't be a need to manually run this in most cases. + * + * @example Basic Usage + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * + * Cache.sweep(); + * ``` */ public static sweep(): void { // Set the start time of this sweep @@ -113,7 +181,7 @@ export class Cache { const now = new Date(); const start = new Date(now.getTime() + TimeString`-1 hour -1 second`); const boundary = new Date(now.getTime() + TimeString`-1 hour -1 minute`); - + // Loop over each item in the cache for(const [key, value] of Cache._items) { // Keep items that do not expire @@ -121,7 +189,7 @@ export class Cache { Logger.debug(`Keeping cache item "${key}": Does not expire`); continue; } - + // Keep items that have not yet expired if(value.expires >= start) { Logger.debug(`Keeping cache item "${key}": Has not expired`); diff --git a/core/configure.ts b/core/configure.ts index 4c3980c9..b489097c 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -12,7 +12,14 @@ export class Configure { private static hasLoaded = false; /** - * Load our configure date from file + * Load our configure data from file + * + * @example Basic Usage + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * ``` * * @param force Set to true to force re-loading the configure * @returns void @@ -51,6 +58,21 @@ export class Configure { /** * Obtain the value of a key in the configure. * + * @example Basic Usage + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * const item = Configure.get('my-item'); + * ``` + * + * @example Setting a default value + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * const item = Configure.get('my-item', 'my-default'); + * ``` * * @param key Key to look for * @param defaultValue Default value to return when no result was found @@ -67,6 +89,14 @@ export class Configure { * Set a configure item * It is not possible to store null values * + * @example Basic Usage + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * Configure.set('my-item', 'my-value); + * ``` + * * @param key * @param value * @returns void @@ -80,6 +110,14 @@ export class Configure { /** * Return whether a key exists * + * @example Basic Usage + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * const exists = Configure.check('my-item'); + * ``` + * * @param key * @returns boolean */ @@ -87,6 +125,28 @@ export class Configure { return Configure.config.has(key); } + /** + * Consume a key from configure (removing it). + * + * @example Basic Usage + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * const exists = Configure.consume('my-item'); + * ``` + * + * @example Setting a default value + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * const exists = Configure.consume('my-item', 'default-value'); + * ``` + * + * @param key + * @param defaultValue + */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static consume(key: string, defaultValue: any = null): any { // Check if the key exists, if not, return the default value @@ -105,6 +165,14 @@ export class Configure { /** * Delete a ConfigureItem from the Configure * + * @example Basic Usage + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * Configure.delete('my-item'); + * ``` + * * @param key * @returns void */ @@ -115,6 +183,14 @@ export class Configure { /** * Dump all contents of the Configure * + * @example Basic Usage + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * console.log(Configure.dump()); + * ``` + * * @returns ConfigureItem[] */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used @@ -124,7 +200,15 @@ export class Configure { /** * Clear all items in the configure (including defaults). - * If you want to keep the defaults, use "Configure.reset()" instead. + * If you want to keep the defaults, use {@linkcode Configure.reset()} instead. + * + * @example Basic Usage + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * Configure.clear(); + * ``` * * @returns void */ @@ -135,6 +219,14 @@ export class Configure { /** * Resets the configure to the defaults. * If you do not want to keep the defaults, use "Configure.clear()" instead. + * + * @example Basic Usage + * ```ts + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(); + * Configure.reset(); + * ``` */ public static reset(): void { Configure.config = defaults; diff --git a/logging/logger.ts b/core/logger.ts similarity index 98% rename from logging/logger.ts rename to core/logger.ts index d30e8198..5b306d22 100644 --- a/logging/logger.ts +++ b/core/logger.ts @@ -1,5 +1,5 @@ import { Time } from "../utility/time.ts"; -import { Configure } from "../core/configure.ts"; +import { Configure } from "./configure.ts"; import { cyan, yellow, red, magenta, bold } from "https://deno.land/std@0.117.0/fmt/colors.ts"; type Handlers = { @@ -46,14 +46,14 @@ export class Logger { /** * Override a handler app-wide. - * + * * @param level {LogLevels} * @param handler {any} */ // @ts-ignore TODO: Figure out how to replace Function with something more sane // deno-lint-ignore ban-types -- TODO public static setHandler(level: LogLevels, handler: Function): void { Logger._handlers[level] = handler; } - + /** * Write an info message to the console * diff --git a/core/mod.ts b/core/mod.ts new file mode 100644 index 00000000..cbc93b47 --- /dev/null +++ b/core/mod.ts @@ -0,0 +1,3 @@ +export { Cache } from "./cache.ts"; +export { Configure } from "./configure.ts"; +export { Logger } from "./logger.ts"; diff --git a/deno.lock b/deno.lock new file mode 100644 index 00000000..fc7368e9 --- /dev/null +++ b/deno.lock @@ -0,0 +1,417 @@ +{ + "version": "3", + "remote": { + "https://cdn.deno.land/std/versions/0.77.0/raw/datetime/formatter.ts": "2862d48a44d2a307795deaeb913773c62704e79e3a21b76f11443f2a8650de32", + "https://cdn.deno.land/std/versions/0.77.0/raw/datetime/mod.ts": "5d31444e61524f399ac17aa75401b7e47a7b2f6ccaa36575416a1253a8f61afa", + "https://cdn.deno.land/std/versions/0.77.0/raw/datetime/tokenizer.ts": "ae21a459f2f017ac81b1b49caa81174b6b8ab8a4d8d82195dcf25bb67b565c71", + "https://deno.land/std@0.117.0/fmt/colors.ts": "8368ddf2d48dfe413ffd04cdbb7ae6a1009cf0dccc9c7ff1d76259d9c61a0621", + "https://deno.land/x/croner@5.3.4/src/croner.js": "a7e06cd5c262c60bc9736d735eb65ae2e401eed3d965c467087a5a575abd8ec2", + "https://deno.land/x/croner@5.3.4/src/date.js": "e5bfdf17750207a00e1399c50bda7be8746429619c9f2fc0679c678aed22febc", + "https://deno.land/x/croner@5.3.4/src/helpers/minitz.js": "8b3824fadd0130b4faf38335a064febdf77c5582dcaa06f443b901e9b8233130", + "https://deno.land/x/croner@5.3.4/src/options.js": "1c6fc9851d195cc94fdd06f947270aa25939eb34e47e03cb5e34f5451926f632", + "https://deno.land/x/croner@5.3.4/src/pattern.js": "e37c2047f04ba80311e5c1ea3764c10410760ad7ab40f669648a9533635982b5", + "https://deno.land/x/discordeno@18.0.0/bot.ts": "b6c4f1c966f1a968186921619b6e5ebfec7c5eb0dc2e49a66d2c86b37cb2acc7", + "https://deno.land/x/discordeno@18.0.0/gateway/manager/calculateTotalShards.ts": "2d2ebe860861d58524416446426d78e5b881c17b3a565ea4822c67f5534214bc", + "https://deno.land/x/discordeno@18.0.0/gateway/manager/calculateWorkerId.ts": "44c46f2977104a5f92cc21cf31d6b2bc5dcfcefba23495cd619dbdf074a00af1", + "https://deno.land/x/discordeno@18.0.0/gateway/manager/gatewayManager.ts": "d82dedc56ef044e1aff108400cad647f3d5c6eb5b574e7ed7b812dc85a260d7b", + "https://deno.land/x/discordeno@18.0.0/gateway/manager/mod.ts": "11f0721de12ab2d923320d877673f617bb77a2222452dd284bf4aff66df25674", + "https://deno.land/x/discordeno@18.0.0/gateway/manager/prepareBuckets.ts": "a92b60fbcf7fb67051504f568932db525e29a6e7c202216ca8583d60ecb8ac11", + "https://deno.land/x/discordeno@18.0.0/gateway/manager/shardManager.ts": "6cfaeae1f367d7978f7b6b505066755a76a29bc46af8643fd5393d757d807fef", + "https://deno.land/x/discordeno@18.0.0/gateway/manager/spawnShards.ts": "687163c5a8d5f057864a9b2803df2b664ae5fef9301718925edc81a4397fbe8d", + "https://deno.land/x/discordeno@18.0.0/gateway/manager/stop.ts": "448cb12cc5f5653bca13fe6fb7b1dfb1da7524c60efab80a4f71233ee76b173e", + "https://deno.land/x/discordeno@18.0.0/gateway/manager/tellWorkerToIdentify.ts": "453ed3d92a6ae23438b4e85c735ed751d89888fa05e36b5d0e43dab73f6fe1e9", + "https://deno.land/x/discordeno@18.0.0/gateway/mod.ts": "d884e34fb4e3e39a7925e0f160af33fad57c9012fa36a5de3e0e5f23600e8aa4", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/calculateSafeRequests.ts": "f70e9eec53db888ae0a2afee4073743d883acd58de153f17298dfbe082136ae7", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/close.ts": "e2e7bc1435c0c13a6e17491463f1b755a81d87b6291711f27ad8b9a89215a758", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/connect.ts": "a774fd7d538daccfde01bad3a91b5ec5e0000f0143a3d81cfcaf78f3174ca6eb", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/createShard.ts": "6cf8c45bd1e2c1c1c532be2353f7f590249d6d541f897fe9c9f4634749bfd232", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/deps.ts": "e96984eb90ac1d22f9a6f215d0263d87fc758ca04d6fd03ba519d8196f347354", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/handleClose.ts": "7a93f5dc12236504b99464876d18ebaf8e0472f942f2c571ea0e8913826a3c11", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/handleMessage.ts": "145682505b8ccb4441f7305a3c8b2c1bbc937e7904e4762f58f6fd0d438f6805", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/identify.ts": "bf82e87e70b588d747f10700fcc614ae072adbc008549171729e85112f1ce012", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/isOpen.ts": "abb14f52b50a523d56678be9b5b901698604d8c791aa63078ef51ae88f02bd00", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/mod.ts": "8a58a564317d9f84bc11a492b6b6ad857a6f3a652e46c6ad6a4c2d0e0edb369d", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/resume.ts": "4713f3c76b5cb9d46a5e839532f0332f530cd2aa035a580f01b8478a3858237b", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/send.ts": "653158bc0522651962f4b2b3a2b9e02c2fbb18540d5432b2f5c1007d160c989a", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/shutdown.ts": "6d9a7479754bac8021a80766b9b73930af52bc22e38e15569346ea3a6315d9c3", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/startHeartbeating.ts": "cbb0bff61f3fb617ea11189e76233e085baa2ec952c66ed9bfa1896f871f01e5", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/stopHeartbeating.ts": "e7b0feb488029720dc21ba5183d0594263b58e2a573af47aaeda95dbbf378364", + "https://deno.land/x/discordeno@18.0.0/gateway/shard/types.ts": "28b4dbb06a3af12919136ebdac748d14cd0fd7a850a6a5968d383449f2de5b98", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/CHANNEL_CREATE.ts": "3b31e183076d49b5f6a005b7b976e14139f3ca52d69659f6fb68039b80e9ac96", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/CHANNEL_DELETE.ts": "655ce49f189016768a10eaeca26835292bc8336d37fcf495013836d3ce557505", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/CHANNEL_PINS_UPDATE.ts": "580a8dd76b052f00a1b8b8e8cdd0ab5eed603cd8372987fd0e7f37710b933a23", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/CHANNEL_UPDATE.ts": "56e716355c503e2877cb1413be331e34fec36d6487fb542840eb7d5db1b79b41", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/STAGE_INSTANCE_CREATE.ts": "d8051cd818ab569b53617dda0e77b12a4a4d0c8c7b8ffee620f0ed9900d06eb1", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/STAGE_INSTANCE_DELETE.ts": "f8fccae29afec36c9cf0ec86e9d8e3aab06e3fbd2d19eec00dc939d37528e305", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/STAGE_INSTANCE_UPDATE.ts": "297f0f5604e429d28db558b93373f912f1ea636dd7cbdbccbd5a9f4e6ceaf9d4", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/THREAD_CREATE.ts": "c7f2190b84255def74cde520c9743ee24cdb68804567abf0db8b75e8a0b4c228", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/THREAD_DELETE.ts": "6d608c49a4d4bc3618c3a01f0bce0b2b87ddd0f5e8696612ec6974c6dc7a0960", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/THREAD_LIST_SYNC.ts": "d3af47b41e9e0c648861f4b85e3a0933c180fbb6ee32af983288f47ef982b36d", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/THREAD_MEMBERS_UPDATE.ts": "12d75e4296535f9af9cfe2ec527c35b144cb6ebc01df87b017fe8680cf5b6588", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/THREAD_UPDATE.ts": "82ffae3c6e031c1485700872caafd29367401bf952c99d7207234e3f3bf8517d", + "https://deno.land/x/discordeno@18.0.0/handlers/channels/mod.ts": "91e2381859886ed05029d57e9ce0d11c6499fe86a1aac04c4c6744fb29bdecc9", + "https://deno.land/x/discordeno@18.0.0/handlers/emojis/GUILD_EMOJIS_UPDATE.ts": "3a86ea7a35ce09ca4e21d0d712c61d129687eb5a44a92b2109f5d4847c0a1daa", + "https://deno.land/x/discordeno@18.0.0/handlers/emojis/mod.ts": "fb22fde276e903e6242ca89d97b59aaed6f60e6839f6444913acaf3f389f0571", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/GUILD_AUDIT_LOG_ENTRY_CREATE.ts": "d610cebc5709a6b8d7776e3137a6d500fd9b2e0186ae5aa4a5e59429039f8866", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/GUILD_BAN_ADD.ts": "cba1779e0770128cb350a51b44ed89db4ccb919cf6d67ed8d760e7935932230f", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/GUILD_BAN_REMOVE.ts": "03a4821425d938f76cf7296d860cb97f49ff045c171fd19c4278ef64434a6d74", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/GUILD_CREATE.ts": "9e7391ea65653117a8115fdfbbad0a9f4d07fc48e4b078313dcf0c4909c7ef77", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/GUILD_DELETE.ts": "1ba57603c0ddb3d50b90acddc1148100f5acc9f6c4b52f37b5b5ad8bda469e99", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/GUILD_INTEGRATIONS_UPDATE.ts": "fdac5b8ccd75f9a57a27731107d7a75a933b9b4ba33e0c824f118592fd691654", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/GUILD_UPDATE.ts": "164fb507ce4544979966d90ee2cbf3c99c7abcabd6ab76fbafec80f15ee37b9a", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/mod.ts": "34450dcd3f62143a6211ec5096eb4e52e17f770a5cc1670b1bc89c62ade87473", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/scheduledEvents/GUILD_SCHEDULED_EVENT_CREATE.ts": "aed7232fa7bc1e4dc0d31b3484aabdc9dea09fc7fd06dafb2ba8fee050613adc", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/scheduledEvents/GUILD_SCHEDULED_EVENT_DELETE.ts": "e7965fb15e87add066d5dddb4ca5c7dd9e44d3ca268571259cd09c137a555e74", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/scheduledEvents/GUILD_SCHEDULED_EVENT_UPDATE.ts": "c63d7073c5b2433afae545baf824931272b3ba2b76b79b35e23482bf1d9d1590", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/scheduledEvents/GUILD_SCHEDULED_EVENT_USER_ADD.ts": "f8f50e9c50e4c0e05ea6e49bef6db4423c01ef23b5029041ba6d816d0afdf9af", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/scheduledEvents/GUILD_SCHEDULED_EVENT_USER_REMOVE.ts": "7cc8e0eef7336e1ea4774204ce9b375db5ecfeaeed4c2e50bae10c5910b9d70c", + "https://deno.land/x/discordeno@18.0.0/handlers/guilds/scheduledEvents/mod.ts": "f0a28cd8b0fcf0909ad2b027234b91edcba97b05135de4b49637143302170af3", + "https://deno.land/x/discordeno@18.0.0/handlers/integrations/INTEGRATION_CREATE.ts": "2d6d4d2d01bab786191297f2c7edd24173263b8de550d8bb190c41d523611629", + "https://deno.land/x/discordeno@18.0.0/handlers/integrations/INTEGRATION_DELETE.ts": "bb87b79956bd353018836714fb8c60966b74518d19fec821b17ca2371afcd7d0", + "https://deno.land/x/discordeno@18.0.0/handlers/integrations/INTEGRATION_UPDATE.ts": "be74f47ab9258c4a30d5054877be7b0ee73648214972ba40cd9f7189e4cf5b07", + "https://deno.land/x/discordeno@18.0.0/handlers/integrations/mod.ts": "6b7588d8963c0f98cbccb07ae1b6043de50a3528784f2fa3d4fc6aa70e7573b7", + "https://deno.land/x/discordeno@18.0.0/handlers/interactions/INTERACTION_CREATE.ts": "081f55732d8d86ee420804523aba5c674589af5eb54ce25e5a22239e433be278", + "https://deno.land/x/discordeno@18.0.0/handlers/interactions/mod.ts": "57005c5079d1cbd6e9f93bfe60e4c97829651884f7d0bb5de46642d8568ddca3", + "https://deno.land/x/discordeno@18.0.0/handlers/invites/INVITE_CREATE.ts": "c0435a2a60ef473ac212abc12b97ee84001a6b67c47c646f69f30b69269dcd24", + "https://deno.land/x/discordeno@18.0.0/handlers/invites/INVITE_DELETE.ts": "c7f3b3e28a90acca37835b1c8f89cb96e2d227785941c2de789fd45515a15dad", + "https://deno.land/x/discordeno@18.0.0/handlers/invites/mod.ts": "b226b3e4f5b16147adfbf9660228f0d353e5a8950eb296357e90659ea7230d7a", + "https://deno.land/x/discordeno@18.0.0/handlers/members/GUILD_MEMBERS_CHUNK.ts": "36661ca5c2d12b9f9ae87d3a797a52a0f30ac4017390c066c5f1645cf74165b0", + "https://deno.land/x/discordeno@18.0.0/handlers/members/GUILD_MEMBER_ADD.ts": "4fcc0daed4c1e9e9ca91c778db7cfb759ec499e6af444d1b5a593e985d0f8afa", + "https://deno.land/x/discordeno@18.0.0/handlers/members/GUILD_MEMBER_REMOVE.ts": "608eb5d110e7d8f36497a9ecf14a990358896879655c678d95f7ff52a30b1dd1", + "https://deno.land/x/discordeno@18.0.0/handlers/members/GUILD_MEMBER_UPDATE.ts": "645406a06ee71fa7cf9c712fb310eb5f8cc16ebbec2c8f88e3b5721237e2f201", + "https://deno.land/x/discordeno@18.0.0/handlers/members/mod.ts": "77976a7904c7ab820c029d76debcc2453dd884a55573884d0f488474b7a88ee6", + "https://deno.land/x/discordeno@18.0.0/handlers/messages/MESSAGE_CREATE.ts": "15ce7ba5d7ed42de886471fa6a92dd9f8a0cf2cf5b3e5c5b0660814b8663d364", + "https://deno.land/x/discordeno@18.0.0/handlers/messages/MESSAGE_DELETE.ts": "bf24f87388b055d0ccfe9169f23e1788d6788f540ff5cb631b295bbe213bfe1c", + "https://deno.land/x/discordeno@18.0.0/handlers/messages/MESSAGE_DELETE_BULK.ts": "397f72939f3d2d5b9456e9318fafe241e421c41de83d408f2f052f941a0517ef", + "https://deno.land/x/discordeno@18.0.0/handlers/messages/MESSAGE_REACTION_ADD.ts": "2a335d2c6a89342d124e7ca0905b667afd194ab42294ef52df23d28a687e739e", + "https://deno.land/x/discordeno@18.0.0/handlers/messages/MESSAGE_REACTION_REMOVE.ts": "f8f7cc7886bb08e2baa4a77b42f1139cf4af4c4d32cdfb2962521f24b25d6fe8", + "https://deno.land/x/discordeno@18.0.0/handlers/messages/MESSAGE_REACTION_REMOVE_ALL.ts": "cac06a4d738e86ec72a2fbb83402982d7fb9eec396e3a4383a53b190f911bd44", + "https://deno.land/x/discordeno@18.0.0/handlers/messages/MESSAGE_REACTION_REMOVE_EMOJI.ts": "4241f53d9f5eab021bc976a2749fae5799bbd4ae1a59e70f5dc2e920fa4b718c", + "https://deno.land/x/discordeno@18.0.0/handlers/messages/MESSAGE_UPDATE.ts": "2093206a9c22eff287b6a8989fc3d291dac7791d11670c68d0a6adcce70efb25", + "https://deno.land/x/discordeno@18.0.0/handlers/messages/mod.ts": "9b760a5a32f2491464ebd5eef55a88c0f214488dc641bfefe3c65816b8a1c87d", + "https://deno.land/x/discordeno@18.0.0/handlers/misc/PRESENCE_UPDATE.ts": "19bc72ded73e938973a47e2010fa88ed257682b7b40f4ff9272908b6a92dccc5", + "https://deno.land/x/discordeno@18.0.0/handlers/misc/READY.ts": "954f0ed0a292c7c8eba8320cc632345e02df24cfaf4ec14ca832bd35c41153ea", + "https://deno.land/x/discordeno@18.0.0/handlers/misc/TYPING_START.ts": "9a5b4dcd9a8dbd08a17f8d884a5ea2d7df3d7134ef0350aef39cd10763579f3a", + "https://deno.land/x/discordeno@18.0.0/handlers/misc/USER_UPDATE.ts": "964f4b51c003be4c09cbda1887fdd1c0c841e852d6f95377e62b703c4bf47cf8", + "https://deno.land/x/discordeno@18.0.0/handlers/misc/mod.ts": "9b60823b169254e472c7f57075e15bee29d32627c123a9037bdded0aa2bdb6d4", + "https://deno.land/x/discordeno@18.0.0/handlers/mod.ts": "b7616067cc062fd4a903dd95a0622cb4f253932955bffc5e7f96d3e039d34156", + "https://deno.land/x/discordeno@18.0.0/handlers/roles/GUILD_ROLE_CREATE.ts": "0cedfdda9fccec57eeadf0c26042e612f820a6315cfada72fc5d16ac71f9e6a6", + "https://deno.land/x/discordeno@18.0.0/handlers/roles/GUILD_ROLE_DELETE.ts": "47bab68f49cf9941edd62b7007b34c0beb575a4d896123761129da2b558fd98d", + "https://deno.land/x/discordeno@18.0.0/handlers/roles/GUILD_ROLE_UPDATE.ts": "a3fd5443422949245fb24023205302ead102484822d1fc17eb21638abc232e74", + "https://deno.land/x/discordeno@18.0.0/handlers/roles/mod.ts": "04731e168f2c896cfca5b0ce9a47679eae3dbdfed9d3c78f1f3f7c4e59b58b4c", + "https://deno.land/x/discordeno@18.0.0/handlers/voice/VOICE_SERVER_UPDATE.ts": "b18886db601ee02e58737f175f335f286ef3f0de558e4465985e7136761cd23b", + "https://deno.land/x/discordeno@18.0.0/handlers/voice/VOICE_STATE_UPDATE.ts": "2b52f6d1928df4099cc03a0f0946fcbdc18df8c17098dbb72ef70258b9ffae2a", + "https://deno.land/x/discordeno@18.0.0/handlers/voice/mod.ts": "5fbf23ba2bf6f921b2f72a660dbf84bd7c10c2d17f26bc50bda366c5218fdb9c", + "https://deno.land/x/discordeno@18.0.0/handlers/webhooks/WEBHOOKS_UPDATE.ts": "d995a409e18c6a209de0b0734373288d57dd1341fa461f04c97f574b3e05ccc9", + "https://deno.land/x/discordeno@18.0.0/handlers/webhooks/mod.ts": "7b974b6515cb6701be25eccb1e4f8c403fe2d925628df43dd356bd7bed7f8a6f", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/announcements/followAnnouncementChannel.ts": "aae23b70be826238b07d612e1d57d78a498849a2428111969bde9554e31aab3b", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/announcements/mod.ts": "948f4ee5a341dae0094636736c7e05f60f559c6168b60b162cb4f5554d2cb4fe", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/createChannel.ts": "4c64c3847ea5241b384ef9ef1146739fba04857967ef8a1e49e2e937455a5d01", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/deleteChannel.ts": "810b6476c2a1825c069832b0c56443677299c9b097d20306cfd46164afc7e15c", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/deleteChannelPermissionOverride.ts": "4b82b8ea40bdd27f8cbc6064879c03cc5cc85894b4d4d71c362653921f5e98a2", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/editChannel.ts": "e8bb361983e7cc7d3514c01c6e91ee4bb1c655b8afd2d32af04830138a8a2a9c", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/editChannelPermissionOverrides.ts": "61c8f99bc6f54cb7424be49b6e61431ae2b3cb1892ba2caa68780be7eefd5b82", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/editChannelPositions.ts": "368f7a517b00a23db8dd04d83fcf47b54e630256d3886b4c09c8324c66f10e2a", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/forums/createForumThread.ts": "19a407d69fee54c0566bdd604bf20d9ed0bae81562e4db20d14fd9c73ffc70d3", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/forums/mod.ts": "b969a6eb5f97199f5efd69915114bcf9ebdd54c7c1c28f67a7575d3d92c73bbc", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/getChannel.ts": "cc65b4ac424a5124671d902362c40bed3e9e83070c2a398c9c48328a1215948b", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/getChannelInvites.ts": "175de2476805e1908c8444c6bfad496487ec53fe67e637cb882c6d7264d0c5ac", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/getChannels.ts": "dde4d5af0c2ac2d0d8189dfb273ce20a6b27f1dda1ecd13ebad575811e1b03bc", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/mod.ts": "1aac0206e6393e64763eacda9fc98fa1ab7013841b43e9e082e76fe9cef29754", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/stages/createStageInstance.ts": "a4b8e5f4f91c49b902b79b693b8433ec87116640ea5ac50930639c0c5159caba", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/stages/deleteStageInstance.ts": "a85ee26a96352bbf9547437139efc8f73602fd36f7fca5fe70c8a9d8efa19148", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/stages/editStageInstance.ts": "3f5867db229d1d4fdaea58191dd4badf2769dcea786b8797371087c5267afd08", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/stages/getStageInstance.ts": "5b0e0df81d5607bbfcd954b8d6be3fc50f42d2ee5fc50dffb1b0f3235f52e596", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/stages/mod.ts": "1a57f96eadaab12dbb1cea18a6e52fcabea2e8771ae8eed17650702b416fafc1", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/addThreadMember.ts": "d7b9bcc230dee323686aaa4ee59f9aeb7d38851127a939ef9ec36304934fdaa8", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/getActiveThreads.ts": "3c97a8bcf1a9fe2e804964540fbb9e108820f6fcc18663de136d5c82e4b7dbf6", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/getPrivateArchivedThreads.ts": "8f7a46421897e07f1397d01d56a48c1e01e082151c7127e9d749668c7dab3aa2", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/getPrivateJoinedArchivedThreads.ts": "caa8c91e9999f79c0cceaaeb641066216db649faae8958de8e5e8a7c203159ff", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/getPublicArchivedThreads.ts": "09e6729950816e726db852c83412d1b1275bf44b7f552f203c8e5c304003ec5b", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/getThreadMember.ts": "f2b80396f2272fd155a9ce92e5faf4ec454da97a4ad9a152816da155dd59e899", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/getThreadMembers.ts": "5e7f26a59bd037e2aa0c85e2d0e14f5cf9480bac470c46bbe30dd158344d8515", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/joinThread.ts": "52edec63af84954786f55c1916d2ce8904dcac51d3416cc448d61032ca0dc9d8", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/leaveThread.ts": "6f868e87b599e7c6e26eadc0d5ccd5d95e628998b16bbe8e4c7348d6565a5c05", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/mod.ts": "70a936adea1c2d1da88bfa92da75aeae59f8f5a382f8de8682fc1cb1e9ce5140", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/removeThreadMember.ts": "528b689ab05403073d8389ad0aed4576f3e86de90e1ca8794ee1681ae7acac28", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/startThreadWithMessage.ts": "d8865cee8b6f786c82f1a402ebcac2b58ca1ff399b8419530a6580667088aa2f", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/threads/startThreadWithoutMessage.ts": "b5fab248fa8075e58c8518c109518ff07a4915fedee05e29593a64431721de38", + "https://deno.land/x/discordeno@18.0.0/helpers/channels/triggerTypingIndicator.ts": "34f06f635c12548629fc79c6348dd09a713385a4aa07fcd09749e1fbd93fa7bb", + "https://deno.land/x/discordeno@18.0.0/helpers/emojis/createEmoji.ts": "fc6718b1f19d70e0eef9e48a3862f5feadeab42caa2504426789dbf6103d461f", + "https://deno.land/x/discordeno@18.0.0/helpers/emojis/deleteEmoji.ts": "d212193fcd34ea47d437870a9ca36f454698ab5551e482b952260abecf1a856d", + "https://deno.land/x/discordeno@18.0.0/helpers/emojis/editEmoji.ts": "5b163a72335ad50fa4345bbcb9e77cb8efdd5a3cebc8a40d8f4c3edf7a003f3f", + "https://deno.land/x/discordeno@18.0.0/helpers/emojis/getEmoji.ts": "4fbe403ddf6069c1ac8c2d65f68f4597917d5499774b4323a3b123cb4c994206", + "https://deno.land/x/discordeno@18.0.0/helpers/emojis/getEmojiUrl.ts": "0d0b8da6275d55228d0144cc93c579fcea51e0c7f502fa21391d3b47eda15761", + "https://deno.land/x/discordeno@18.0.0/helpers/emojis/getEmojis.ts": "776eab9413d0cb8364d7bc0e6b1fdf38b63451a81162ea97784ded0b2bb43a72", + "https://deno.land/x/discordeno@18.0.0/helpers/emojis/mod.ts": "0c9b2e86b392aa3d698702dc04e350b4d35c9173fdf868bb3e3a0dd7d89a30ca", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/automod/createAutomodRule.ts": "e0f1fe34f92e3fb0c9a6e636e671853bea08132e4963287665486ab99cad710c", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/automod/deleteAutomodRule.ts": "b5b3262ec3a47e7bfca2418082a005adbd2832a70e77777af5cc558278648f5f", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/automod/editAutomodRule.ts": "0655662b1a8b030d4a1c51d04507b5fd42a88e74a3d7046befb253c6c73a0ce1", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/automod/getAutomodRule.ts": "8579fbc14fa7d222c0fb8e0f9a7ddc025870657190b22c63f7f3a187b1c34001", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/automod/getAutomodRules.ts": "79ac5eb57d140919a115f25edb2c9f2e94e41fcb55839e56781d093aedce0e1d", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/automod/mod.ts": "5d1eb9f8501d1f9e929025be86028c8714bbd93f5f2a79bd6506596c0c1dbc1e", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/createGuild.ts": "5361278b053acb5081e79d40f11f975e0ec69e6a2b6f673d5fd708ec3d6c9186", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/deleteGuild.ts": "5b2d6b581817981528b8be85faeae42f6e098e241fc36e2069374a348f3ec543", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/editGuild.ts": "78bc0e66d0b953521b0fa2bbc3d6d0459ed2385ed2aafd8bb7cf7529cce5bf35", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/editGuildMfaLevel.ts": "14b10e70eb731b57ca169656bac2c13d8b97ed7028fc20fcdf2230fd843a09fc", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/editWelcomeScreen.ts": "dd25c4470acf75149bf18ab34b4b35871920b430ceb709654aeaa6c1b28eec1f", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/events/createScheduledEvent.ts": "ae526707edc545f98ce23cf951d10a9ef205a64dce391a3669a832d5973de821", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/events/deleteScheduledEvent.ts": "e556878c5fbfbe0c2c794ef8d9cf2815574a6372a82a58cb8cfa0c75253f2ec8", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/events/editScheduledEvent.ts": "c0cee76fdcd477efeca2787b7372b8bd21ad8895535878fedca1ae8a137d582f", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/events/getScheduledEvent.ts": "6d909db7808a8a2f96a824106e79db7aaff392e8c24cd2e47fac9b6538b067d1", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/events/getScheduledEventUsers.ts": "2bdea83518bd86f64dd0b997de375fd1840d3cb60256f15b8be55f6545c5f7ba", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/events/getScheduledEvents.ts": "5f98bb604e439690c5d6e5b93e6962255a89f0e3d58292dcdf0c58063c68b976", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/events/mod.ts": "ae3428a9164ee36a14243900dc4fe699a1b9b85c9e3cc5c073882e957f92db90", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getAuditLog.ts": "16cd657d472484ef8eaa6ec520dda8e800203593a2f8cea449276101b0022aca", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getBan.ts": "d071e9f0ac8dd372ae777b4b759c79d9b1bd1dabdaf1f1de71ca951cf29c4950", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getBans.ts": "45a72714dbcfcec84df81fb8e920d9c373080600365ac7a1e7fa71e888533fa0", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getGuild.ts": "2726a90b09e1b20b24e41e0eb53dfef8e2c804a59dc3114adb09b6c4d91ab235", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getGuildBannerUrl.ts": "d8f54da9d84a6446ef4d8ff04c4317f16bf139ce663ab2e95655238c17ef9743", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getGuildIconUrl.ts": "31d7fec2fa0b5008e216cebeb623216df9a2fb890602ba7db56e1501dc1813ed", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getGuildPreview.ts": "97b2f5e30084e066f65bd86ec31e9f79a4602d23f6b351cc30a4cf62fd786415", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getGuildSplashUrl.ts": "b350b62886cded7ef2ede24b8e11da72d2c67829fe171b2c599070231635999b", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getPruneCount.ts": "c1b42a2bfd11b6e8514c76d61420eb5ef2e95d36b87ab4fe0c3b16538a0eb949", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getVanityUrl.ts": "a392a31a6d0e1f88373dffd6bd28f8713b2c5245e6389cf9ff6f38bdae039f30", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/getWelcomeScreen.ts": "fc7abc71de5c19087192c8000e1ffd45307d6be8019467e751ee2e57af855c5a", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/integrations/deleteIntegration.ts": "c2a829750b2626e3ab88c36dc9e4d4cb292e14bf182b4fbd132644979ad3d240", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/integrations/getIntegrations.ts": "75baf8e19ac3250b824df055bbbd49aa17ec93938776e99f9dab6799236426cd", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/integrations/mod.ts": "971be8c462243af6db336545e78d46d5b573b6b978eb30ccadea345920de0c34", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/invites/createInvite.ts": "25fe725a19a27fc695c9c90557bf07896a2050834603c59c97896cf4e8e8cab6", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/invites/deleteInvite.ts": "7d58565b833fbb7bf002417e7050398f648abb611415060748d512f1d0547c71", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/invites/getInvite.ts": "000e46d77ac8ca8f1c433c516467cb9a3ab1c6ce143a30c276b217a476c5bbeb", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/invites/getInvites.ts": "3f3fe66ae3da0ae07bc2d89ed95f8097640c286a95f3d0fb00bb6665d8314245", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/invites/mod.ts": "bc8f68c4f2da324104c44b598f661480aa3e6512dd6dec1ffab780afb1fdf0c8", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/leaveGuild.ts": "70785da8de9809326075598ff79eb6fc8066c90469a4943401ac146137070a56", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/mod.ts": "5a087689e8f5dfc359f7856fad177466b18c0c4814cac55c47919dfaca69158b", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/voice/connectToVoiceChannel.ts": "a656d1921f6d592ecc89e6b44f57856161e0d0c6c89e0bf2e9dbc91842d3a193", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/voice/editVoiceState.ts": "e01ee60cacb79311c0504d21cab017ddbf8f848ed0085daedb2748c77f4a7d54", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/voice/getAvailableVoiceRegions.ts": "342f89b1aea5492ac015131a42352da565f02181647e065e6e3f8968e9230d6d", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/voice/getVoiceRegions.ts": "dd7c5b1f92a9305a8e0f483d3e1828b12049d9f4e414623bf3c4d4fbce41e09a", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/voice/leaveVoiceChannel.ts": "e58cb1a3e4de76af5aff173e09bac8d1f4897d24defc81164def9f39356748cc", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/voice/mod.ts": "66740600945538976f33cc93567a1d56b25813d2e68f38c4adf39ce6feeb4236", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/widget/editWidgetSettings.ts": "9e782483c30c5cf763ca877eaffbe981af63a9ccd83a88847595add5410d5a13", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/widget/getWidget.ts": "95dc9515e126e4d0c6c9ec61049201874acd129dd52431c909d0cf2e4065d635", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/widget/getWidgetImageUrl.ts": "bfb5fb302fa4c7ed245b2b8e31e1ccb67d40a5cc8c700b86aa4ea574a81f1c63", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/widget/getWidgetSettings.ts": "02af061e32959e95de9bf9a7dcab2b4455fe263f4952888b6a622029f6940c2d", + "https://deno.land/x/discordeno@18.0.0/helpers/guilds/widget/mod.ts": "ee930d39d2d54d251ad85c0f77ccd7fb9629b25aa18fa30bbcdbe11c2855d1d4", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/createGlobalApplicationCommand.ts": "49e8460e7469561839f54f42176bb3259f3c61005581f6c9fd6be43813a4d6ca", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/createGuildApplicationCommand.ts": "be30bd72480dd8b2f8b8140b55763a33a92764835dbc6268355c6f5cb5257002", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/deleteGlobalApplicationCommand.ts": "437d84b1a641281c4bd3a0dd60b71ab139dff118a3b62059c97e24b253df7fb5", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/deleteGuildApplicationCommand.ts": "84f0844215952231e22ab24cc69e68fad00b565dbbc05efafc165f2a35e98c7e", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/editApplicationCommandPermissions.ts": "cd50cca4eaea9a62dce04cedcceb03ef7fdaef1f053e178a382793fae55e0f83", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/editGlobalApplicationCommand.ts": "0ab7bc1e399f1e5bd60e28f8f289c9c30fe2001ae81232c0889ad8927487c9e5", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/editGuildApplicationCommand.ts": "c3ff698832e5f5a9d844fa96a3df0268a83f3ad4fdb8d9840fec682b145809c9", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/getApplicationCommandPermission.ts": "8f2d493937389354cfbbfe654721784c966be45ce34a37ab79e203017b6248a8", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/getApplicationCommandPermissions.ts": "a8778945c47d3c5e14dfa52daa9651e937da73324cbf11864ae32da86bd41d33", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/getGlobalApplicationCommand.ts": "1efdf81d7fa24289890e65332ef26da4b66978471c2bf58a08a62c7b11268cf8", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/getGlobalApplicationCommands.ts": "cbb2c4bef74b9768d521bd134fc967c356475596783dcebe475da6c90f7924c1", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/getGuildApplicationCommand.ts": "137b09b1b2335f604970b7cd39b3fea84a8405a3fb52f0812f1b1e9b591a344b", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/getGuildApplicationCommands.ts": "01199f85482619639be729061bf43df31f7914e52ac9abce8fca47c7e9bd8867", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/mod.ts": "819587332aa0900a9289cb955dad2f438e3b586cf3e3a62fd8dd1f54e4bb4b15", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/upsertGlobalApplicationCommands.ts": "f8db384f9ce2850e3fbb3d2bf90ee1cd40253c5109e32b496106c4b189f15144", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/commands/upsertGuildApplicationCommands.ts": "4c2233fee33d221c38e75d4b30c229c9c86ddc6288ce691fe802feb931908394", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/mod.ts": "734a879422865899f5e87912af0e4dff83de7132d4c875cb2c021f07997ef163", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/responses/deleteFollowupMessage.ts": "560080e24bfaee8cbb31fd510995234eb45f2ee467c89863378a0368aa0cc16f", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/responses/deleteOriginalInteractionResponse.ts": "5761ac422d3979f4023189a5d26e580d870093b572235afe74e99d97fc4c5e76", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/responses/editFollowupMessage.ts": "56e377fbcdbc6bd7afe1cfdec8aac50921b4ee174942c342f9f6bb3d458ff254", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/responses/editOriginalInteractionResponse.ts": "5d870c2f59a615ea571a7d2e4bb9a688a52e986e66385143711d7c58c528bcc2", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/responses/getFollowupMessage.ts": "5cc166cfced967e7dec57526c6bde3cc3ff66c14497d00595adb6f832ba8cf5b", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/responses/getOriginalInteractionResponse.ts": "fd754d2d6a41d33affb7756b04b7fe176c2e00e08f45648b4dbc1fbcf3fcb134", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/responses/mod.ts": "b1e9d06f552aa0c880e7dd3491878af405cd0b9b55da5cfb28f1dcb4d8bf11d1", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/responses/sendFollowupMessage.ts": "56692227ba540dd0eb910833b32bf9b620c5353e98f191df76c7859dbaa67aab", + "https://deno.land/x/discordeno@18.0.0/helpers/interactions/responses/sendInteractionResponse.ts": "ffd7b30e80a276eff7e8e685ae7399d6a44d04c803c144b3c14d7bf4f10ff0be", + "https://deno.land/x/discordeno@18.0.0/helpers/members/banMember.ts": "3dc6fe3608e4c9e6ae07edf049ce683e61f54532e9e3f5072b7ae918a4a3a705", + "https://deno.land/x/discordeno@18.0.0/helpers/members/editBotMember.ts": "09f3c8437a4c51690dfccc9114199e9544d5fc43804f33206aa172162b87b444", + "https://deno.land/x/discordeno@18.0.0/helpers/members/editMember.ts": "69e6ed21ccc45b0d1fff6cc8ebe47dd456ad4d575cf04fd23ad73dd235c586bd", + "https://deno.land/x/discordeno@18.0.0/helpers/members/fetchMembers.ts": "640f136dcd68facef890f2d2e913bfbb2988235615916dc7c3a0f0f2a521e47e", + "https://deno.land/x/discordeno@18.0.0/helpers/members/getAvatarUrl.ts": "da5e05e2a70ce09b27867c3e6adfdedcb665cc073a4a1fc50175864514f836b8", + "https://deno.land/x/discordeno@18.0.0/helpers/members/getDmChannel.ts": "8e1d0c44adb5a30fc2817a034d535348546262861b706335c423da63b55a4be7", + "https://deno.land/x/discordeno@18.0.0/helpers/members/getMember.ts": "b519fdf2d7a2a0f7ababfe3465141477e4f294cd84caf561c49d712b915da18d", + "https://deno.land/x/discordeno@18.0.0/helpers/members/getMembers.ts": "e93536f1cdd233ea12305172d5193c7152f47e5f638652eb8225dff75feef5f9", + "https://deno.land/x/discordeno@18.0.0/helpers/members/kickMember.ts": "9fc2e8611543bd170b748086543d3807ddc549ba97c373a04b341b2746548333", + "https://deno.land/x/discordeno@18.0.0/helpers/members/mod.ts": "6e2165e135f6e7d34d847bcf870143ec574f230c26391ad6e9516d92b380884f", + "https://deno.land/x/discordeno@18.0.0/helpers/members/pruneMembers.ts": "62fd7aa7eb03474ad30bdf9c8891aff69976575a0278a17ba8a7bd6f27b69857", + "https://deno.land/x/discordeno@18.0.0/helpers/members/searchMembers.ts": "bc2436e47b8beb316ca38e1d11cea5305a25f923cb1ee7386583bf7706e4f567", + "https://deno.land/x/discordeno@18.0.0/helpers/members/unbanMember.ts": "f188379c1add49b2c928eda59fbdbc4604cc7b6d126020fb39ebfaea799b2094", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/crosspostMessage.ts": "681fd0aeed7593c1ba43c04ffaa4ae6fb2e3a5cabffe4dc22a042a7b4ebb7558", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/deleteMessage.ts": "ba7b712dd29a777e94e004a218e82bdfcaf6c3ea4774210fbe87e5bc1e864b9d", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/deleteMessages.ts": "d7172a936cf89632ed1068bf3ed61947643060b4d32dd497630e45423176295c", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/editMessage.ts": "bab1cedb8271eab872ea496543164fe2e5664272d9e6ec770b595690aa270709", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/getMessage.ts": "d2b176701c26e01310c4a7c5e61c7cb9d9eb4f33608944befb8dd06fea460cfa", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/getMessages.ts": "2f3258a8c00f67bda48182e8f000d4e902520880158540c5c719c9abd85812c8", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/getPinnedMessages.ts": "df4e213740ed9c4710f5d65371f414614df60b348a20ed6c7ef83a1ddebde08f", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/mod.ts": "1fb89a5a70cb1b9e927c5bbc3d746cfee1795874cadf7ed94daa5e74138d7cb4", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/pinMessage.ts": "0a9c24b6aeb9f8e9c024fce2db3e3d4191f594990b8ee5b8d37012332d04a2c1", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/reactions/addReaction.ts": "2e9b82c3e738bd55bfa6bd38ae8cc99ffcfc23e33d435e70cd248ee3cdadd5f0", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/reactions/addReactions.ts": "9c3dc066b146c968b8ba39680ffb63d23796df148ff657cf5eb41ab04a38cfec", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/reactions/deleteReaction.ts": "3274cd5312fab0463a5bf101bf0dc9f4af6f5a9ddeae5e961499a88eaea3d697", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/reactions/deleteReactionsAll.ts": "8e15ddf88c50342ff84539a8c9c298fc0aa8380550ba35d0f4c4a6bbe10680f2", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/reactions/deleteReactionsEmoji.ts": "d4c2c0fad2a9448ce1d28797353f8a08793d5bb7b86eafbeeb889c5829567f57", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/reactions/getReactions.ts": "11c505c7ca4c7938605f4075a70786a1f7f92c73919bf884d1e8fe99a2aee785", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/reactions/mod.ts": "aacc08f1fe8deb08787fc114d4c2657baa08fbfa1fccd7cd7b867df554938a1e", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/sendMessage.ts": "40774d6a5f7086b1d64f1106073c3501484a511703c87a74b06695724bb87b66", + "https://deno.land/x/discordeno@18.0.0/helpers/messages/unpinMessage.ts": "471a45e1cb77726c2c9be7c938216e6c6b7ba17e0d09d1907f306dd66e9bedfd", + "https://deno.land/x/discordeno@18.0.0/helpers/misc/editBotProfile.ts": "ecbeb13cef06ce8c1a6f445774f80ae3515934ebf0da953fb32339c68e046b24", + "https://deno.land/x/discordeno@18.0.0/helpers/misc/editBotStatus.ts": "ea2b89437ac396af2d78fb8fd182ab6537c64ecf62a59634305cb617f7f97bc9", + "https://deno.land/x/discordeno@18.0.0/helpers/misc/editShardStatus.ts": "525befc88f8f2dda7c9564ddf5451aff2f8acace6a62e8a22fb1f974ed6cd663", + "https://deno.land/x/discordeno@18.0.0/helpers/misc/getApplicationInfo.ts": "b5afd7d7c6a42dd810864bb14c2a486bb216368c31c1f1704668603b7223ce2f", + "https://deno.land/x/discordeno@18.0.0/helpers/misc/getGatewayBot.ts": "cd80410fc62e9eda9b374278bdbb7b5a6d3d8da5c13969ff231ee576cc39156f", + "https://deno.land/x/discordeno@18.0.0/helpers/misc/getNitroStickerPacks.ts": "fefc173c5b4796b21ed98f0db4b34f7cf6ea6ad5b5db476d667fc152abac661f", + "https://deno.land/x/discordeno@18.0.0/helpers/misc/getUser.ts": "3833adca7024ba3ef9d84e53fa8695f7f028590ff29bed6ec99ca2714db7fe8a", + "https://deno.land/x/discordeno@18.0.0/helpers/misc/mod.ts": "74c73a1828f29cbdf5bf36821276b168ad0334065e6210a0ebb66619b17a992e", + "https://deno.land/x/discordeno@18.0.0/helpers/mod.ts": "b0a87ac1f272302c4502517a433c73c9643c4cd772ebc04f6a542b9785f4570b", + "https://deno.land/x/discordeno@18.0.0/helpers/roles/addRole.ts": "f44efc4425c5494a2e8441287195fba968c30d2a61b275b34eab4cbf951cdf68", + "https://deno.land/x/discordeno@18.0.0/helpers/roles/createRole.ts": "798874cf9033f58ef016f342602ad242e6429f07fefddd5bb2ce2b00cb844070", + "https://deno.land/x/discordeno@18.0.0/helpers/roles/deleteRole.ts": "51b5b62d33b3d6d3e5fd6f4037cd0fca891ce608d2b7bc0d79981aaeada1ad91", + "https://deno.land/x/discordeno@18.0.0/helpers/roles/editRole.ts": "00011dfb356e1f427c8261c1be9491b73109a8a12b7586e781c0f77954f67ffe", + "https://deno.land/x/discordeno@18.0.0/helpers/roles/editRolePositions.ts": "69359d651c800779ac7775cfb2178e577dbb4ea3511ccc58af9262abd409058a", + "https://deno.land/x/discordeno@18.0.0/helpers/roles/getRoles.ts": "1bf991efb5c9d6d9dfe87c720d24f47b5b1a9f7fb92c7b0a2c2037c3a8cc409c", + "https://deno.land/x/discordeno@18.0.0/helpers/roles/mod.ts": "b9dec4f420c57dde0a096d615b68b55682dcbf7aac50048e8df909d354df5a87", + "https://deno.land/x/discordeno@18.0.0/helpers/roles/removeRole.ts": "ae3cf5e39b711800c41fc74b4ce1bb7a9d97b23e436b544c577d3887e865bbfa", + "https://deno.land/x/discordeno@18.0.0/helpers/stickers/createGuildSticker.ts": "8204360975b5e74fe778219881538600e246a35dd6c83475bc722c031b8be24b", + "https://deno.land/x/discordeno@18.0.0/helpers/stickers/deleteGuildSticker.ts": "7487ff0421f7320dcfe40f44660e47e8d5e1bc3617a86659bba3f8d58b0b2cfe", + "https://deno.land/x/discordeno@18.0.0/helpers/stickers/editGuildSticker.ts": "5cbacd5f9fb763bd3210a7e31f1810187c731a1613bec1cd81747abf681ea92c", + "https://deno.land/x/discordeno@18.0.0/helpers/stickers/getGuildSticker.ts": "bcd54189cc52fef8421ed7f645a56b64560b0aab9d06be5deb85170c7f2e1e1a", + "https://deno.land/x/discordeno@18.0.0/helpers/stickers/getGuildStickers.ts": "988512f633db3aae201239321acf46004f0826b3db4d578309785ba66fbf95cf", + "https://deno.land/x/discordeno@18.0.0/helpers/stickers/getSticker.ts": "5f9567d2152b74e5cbcdd666a6792b5fb2c91fbde9b332b7445970c623a8f33b", + "https://deno.land/x/discordeno@18.0.0/helpers/stickers/mod.ts": "2874ae9fa1a90ca62ea2c534654233849c78068ff9e8a8179faa3417d2e8136b", + "https://deno.land/x/discordeno@18.0.0/helpers/templates/createGuildFromTemplate.ts": "96cbca166348b5b5ecd33cdea68f0d71b20152e60017b82ec8a11ada04c26afc", + "https://deno.land/x/discordeno@18.0.0/helpers/templates/createGuildTemplate.ts": "251644641d451a134efcd741d3317d36a36379e36ee3db87cd402bab2c1b1f5d", + "https://deno.land/x/discordeno@18.0.0/helpers/templates/deleteGuildTemplate.ts": "9264e941ad21a928d14941fe130cba45015efe2239b5cab0bcd83acad67152aa", + "https://deno.land/x/discordeno@18.0.0/helpers/templates/editGuildTemplate.ts": "700e295973cf2a5607a4cfafcb781793acddaca2743dfe4983f980480e9a9782", + "https://deno.land/x/discordeno@18.0.0/helpers/templates/getGuildTemplate.ts": "9975079b8acc6e91cdf548fa568a1913a3c92222c0deb5f9836d11a6f842b6d1", + "https://deno.land/x/discordeno@18.0.0/helpers/templates/getGuildTemplates.ts": "2097321ca6d15db97268b522ef4c0659a8327f8fc47c9a6d7e48369a283b6f16", + "https://deno.land/x/discordeno@18.0.0/helpers/templates/mod.ts": "d43d90c92258e98350fed109481eecc9c789cc068d425650e584edeffb8eb376", + "https://deno.land/x/discordeno@18.0.0/helpers/templates/syncGuildTemplate.ts": "a91610d0fa3c870f9c1397fc9968fe247c44bf04f923f69e9a95a17de72fe771", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/createWebhook.ts": "cbda8371f73e1fddb4be3ec3ee3243f09fb6753b28df45cba0b76a01f468419d", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/deleteWebhook.ts": "71cbc17d1f8265adf2fb964f4b0761bd3c0b273344dcf2a949b6e0d4cac6e3a9", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/deleteWebhookMessage.ts": "6fb6064a0dd1a968d1717cb7d2a714479711063462d72f7f196f5e5430bc74ce", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/deleteWebhookWithToken.ts": "0966d5b0841b167c313ca8ea2dd300e599824319fcb3dd6b48ceb5fe9e1ebff6", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/editOriginalWebhookMessage.ts": "3410c95ae90afacbcbd058c43df6e15c5a6ddb5a8abd1d40e8aabb5c1a4e9626", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/editWebhook.ts": "a2b718e52783aa3a11128d96624f97cc8e4ea18695e14f5b17c87e0d5fe279e8", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/editWebhookMessage.ts": "3e92c9988f86cf64b6d7b287524b3b347f7175dd25388290be0a3efd6c3a602a", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/editWebhookWithToken.ts": "c388f0a1e0323b0f88dc576b602362855f1a3e0b241cb2f5aa3e56255c4e9607", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/executeWebhook.ts": "8c9f8dfa9c870e591680b2d7d79ea03da616c45a3dfa2e65e81f1c995227f625", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/getChannelWebhooks.ts": "e7aaddcb3b5315061dbd820747c184c6b5e3ddba0b777aee4c94287768d8aa19", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/getGuildWebhooks.ts": "45c5efbeac51add558281b473e0653cc96896063f4095f3fe18f460d85b11eca", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/getWebhook.ts": "0592eccf3e632c02832e76f44e610666ee874ef35b773fa19a4b4a9233361610", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/getWebhookMessage.ts": "8b38c1f9fd1ba0168e9e924f0a853b683233b986e93f63d82d1f51549578631e", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/getWebhookWithToken.ts": "f5d314d0bc8ca8ab35f3ed6834bdc33cce0ced33761cc4d8ea6b2d01e2e57f45", + "https://deno.land/x/discordeno@18.0.0/helpers/webhooks/mod.ts": "df2aaaacc457b27b59d132dd99e74c447d181e7b26b866180cd92364e0c698ea", + "https://deno.land/x/discordeno@18.0.0/mod.ts": "f76db2786e39c24f58b221512a1386677e71a6163668de7219c16d971e4c9e77", + "https://deno.land/x/discordeno@18.0.0/plugins/cache/deps.ts": "e7421b4414f8f366eea6cd279e18a6d476833c5e93ae8dc8b073209520816b40", + "https://deno.land/x/discordeno@18.0.0/plugins/cache/mod.ts": "de20cd90fc3f9a7ed239e0a00985d2083ffbb53dcb392daa3a9a9959266fdb30", + "https://deno.land/x/discordeno@18.0.0/plugins/cache/src/addCacheCollections.ts": "b8680e417c427a187099ef86b0cac6782753f775682e681c8644025c1ca8aa12", + "https://deno.land/x/discordeno@18.0.0/plugins/cache/src/dispatchRequirements.ts": "d7fe984e031bd3fbdb96bddf6a134a37e3e3825d12db9c27a317e61f1043fa6a", + "https://deno.land/x/discordeno@18.0.0/plugins/cache/src/setupCacheEdits.ts": "c07d49ae381a3a2ce0d33ff9621519cd09003424ec0da1f7a90218d4c9344065", + "https://deno.land/x/discordeno@18.0.0/plugins/cache/src/setupCacheRemovals.ts": "6510a20cd1e0566b55ecf07833754780a71a2e36410294f8cb2f5b477bb495c1", + "https://deno.land/x/discordeno@18.0.0/plugins/cache/src/sweepers.ts": "208861ebd8659b930e1d861c09bfa169e0f217ea4bd53195700db2a9d73b93bc", + "https://deno.land/x/discordeno@18.0.0/rest/checkRateLimits.ts": "52e7b62c5d60ced4acf141d76c4366cf113caee807fcc6c7414cc9ce55ae6445", + "https://deno.land/x/discordeno@18.0.0/rest/cleanupQueues.ts": "c034bb1c129e1d01a3061ed6b87b698c2f6a5f91a1037bbf25e786b0494a35b7", + "https://deno.land/x/discordeno@18.0.0/rest/convertRestError.ts": "77159dc9684732807ac1b3d86e089371f7b4522167dd67f3399c81d4a800c853", + "https://deno.land/x/discordeno@18.0.0/rest/createInvalidRequestBucket.ts": "0dcd335124c993d8f3fe77e1f4824ab85b0e233ab0e73f71f168bc2401e7d6d6", + "https://deno.land/x/discordeno@18.0.0/rest/createQueueBucket.ts": "0c0f70e2d2581cc93c21f44915087e7f85892d1d33a3680f77a08f087ad5fcbc", + "https://deno.land/x/discordeno@18.0.0/rest/createRequestBody.ts": "8090742839045bbc1018f971a9e5a8c99cee310b6aeb08138d15e66c58d2a38f", + "https://deno.land/x/discordeno@18.0.0/rest/mod.ts": "ba7b2696916f1c7d1a6d9b0cb9a534d49aa60e21811dbd28859048b950cca0b1", + "https://deno.land/x/discordeno@18.0.0/rest/processGlobalQueue.ts": "c81eacfa8d10925440d71b12797950d3259eaeeac40150767d5ee9030d1ced09", + "https://deno.land/x/discordeno@18.0.0/rest/processQueue.ts": "1abe7716e45a50f04d877d1a6ba398889b0fd038269c949d7c236b4b27e61b6d", + "https://deno.land/x/discordeno@18.0.0/rest/processRateLimitedPaths.ts": "d7f8c464f76cfcb8fa761a4c3249a80fa156f090c57c0a1284d179b7cacae8a7", + "https://deno.land/x/discordeno@18.0.0/rest/processRequest.ts": "2739c769254d2c616ba7c23620596789dbef0dbde49a4a1947a20f0bb956eefc", + "https://deno.land/x/discordeno@18.0.0/rest/processRequestHeaders.ts": "63338cf9803ce46f3e70525f620e5e9ac646504e63c8b2f763613b44745d987e", + "https://deno.land/x/discordeno@18.0.0/rest/rest.ts": "3e47bfd31fe2901e581caf9dbee6f0bd428ac436a53b0eb37a4ad0329baf7488", + "https://deno.land/x/discordeno@18.0.0/rest/restManager.ts": "5264368f5fa2e0235bccc0579c839375f3e5d4ca45f3de9560453441f62fbf2f", + "https://deno.land/x/discordeno@18.0.0/rest/runMethod.ts": "091f7da468ede8451502a9990fc5e0322fff0f510fe1be02f631c42c98d0df87", + "https://deno.land/x/discordeno@18.0.0/rest/sendRequest.ts": "c3ee092cc9f97aaa4caab428d22d9026510cf60a4cb63c5f2be9c092741d558c", + "https://deno.land/x/discordeno@18.0.0/rest/simplifyUrl.ts": "1b2661a776bc5c2fb84ee73312926183f51f11532e7d8f62ce44ba823c992295", + "https://deno.land/x/discordeno@18.0.0/transformers/activity.ts": "bfb5245a7bd8c5fbdfbef8a7965f744368264f07b726244d65a578ba80542125", + "https://deno.land/x/discordeno@18.0.0/transformers/application.ts": "cd41c186b3e54d1060233514498b8ae0e4be05bc8e36d854f0ed011f4577c0ab", + "https://deno.land/x/discordeno@18.0.0/transformers/applicationCommand.ts": "ab793ac543e5f472396eed24a9c06704429dc8b60d70a0c6faebe9e595e01a25", + "https://deno.land/x/discordeno@18.0.0/transformers/applicationCommandOption.ts": "329112f7a60df518af0a835e46cc79d744c10ddd4971ea8d050ea3b4dcdc05ec", + "https://deno.land/x/discordeno@18.0.0/transformers/applicationCommandOptionChoice.ts": "2118fa6989af6006e7266ab9599f1402cfcb9211227e296bab019e92ee0e2875", + "https://deno.land/x/discordeno@18.0.0/transformers/applicationCommandPermission.ts": "8d13f217325ce9d67068464fe2c9d42a07d152fc70558e2c0092b49010419d9b", + "https://deno.land/x/discordeno@18.0.0/transformers/attachment.ts": "8963729b4fe321bc4d60d13d6ead7e815729dba42b28d3d3117c637d009545a0", + "https://deno.land/x/discordeno@18.0.0/transformers/auditLogEntry.ts": "fdf6e1d7e4ba1b1ea3fd2d8bd21968dc9026139c1701952f485c709b7702a319", + "https://deno.land/x/discordeno@18.0.0/transformers/automodActionExecution.ts": "cdbc1570678e8c0779972d6897755208fc73bdc6921db24817ad9b385fa2a3eb", + "https://deno.land/x/discordeno@18.0.0/transformers/automodRule.ts": "83ea7f0f51568e231e9f0a76816c6d33a5d82da11c366e72dde935ee1e0d1a1e", + "https://deno.land/x/discordeno@18.0.0/transformers/channel.ts": "707d570b297b0d4146e373d68a8f8ed7cfc637e716ad17afea3e9e7031e801a9", + "https://deno.land/x/discordeno@18.0.0/transformers/component.ts": "503a2b32110587f5c763a59d1d746b79efeb82d2be6f6e97f1714e1ffb02ce4f", + "https://deno.land/x/discordeno@18.0.0/transformers/embed.ts": "abe227b8d2b9f062c526cdf279656703180c8e5f44c3691080ef5e32c0b3156b", + "https://deno.land/x/discordeno@18.0.0/transformers/emoji.ts": "58da6a8eb8c5cb9573bf43608e5a34ae2649f1d0a67fd4e74d99b5e8afe84d1b", + "https://deno.land/x/discordeno@18.0.0/transformers/gatewayBot.ts": "0c7dfebdaf142462fbd6cc94c61a64e8f2032834c4308b7ad06e493172c4fedc", + "https://deno.land/x/discordeno@18.0.0/transformers/guild.ts": "9e6e646d0eed2205f866008fc0b81edc1451c984c8fc890265e9b4fa8e1c7f9f", + "https://deno.land/x/discordeno@18.0.0/transformers/integration.ts": "0bda973c99949f906fe823e91d55b329a6da520eadb9eab8040946b14f8121f6", + "https://deno.land/x/discordeno@18.0.0/transformers/interaction.ts": "eb273d1fdb3240a8a40a5fad4a23a389582c5de0ae609913d1117f7f49458b20", + "https://deno.land/x/discordeno@18.0.0/transformers/invite.ts": "b9aeb5c51f653f11f2ca3974eab37fe28afc5e378e2f74ae975e0ccbb1f78027", + "https://deno.land/x/discordeno@18.0.0/transformers/member.ts": "ee82dc0c90d002d7f1ffdad8c86cb2ca05fa6d522173cf9f96f4912a63f695e4", + "https://deno.land/x/discordeno@18.0.0/transformers/message.ts": "cc5a068a00d497b98edfe83116486330636d026d73c06ec3dc7f978a3d2e38e8", + "https://deno.land/x/discordeno@18.0.0/transformers/mod.ts": "a29fab81b5d41439a854ed5d8d708be202740b035599284c637def13eb9f9e5b", + "https://deno.land/x/discordeno@18.0.0/transformers/presence.ts": "c4e6e468be742665ca904cbf1377613256a6f940d133c92838cef7ec48b6c9a7", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/activity.ts": "4a3e30ffd3721c737e1697590cb9849b584a6ebdf28af13b973034289c134b42", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/allowedMentions.ts": "1978ecb464310d8f2bc1baf7e67ede45a29b67929c0b647463b65efc50d8ed1e", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/application.ts": "3ddccb0063a9ddbb907bea57a0318ad6d00fc1f34acbbb531fc686a10668e7f3", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/applicationCommand.ts": "647418c1f7f175f40557adcc3c22449e965f3813f505ef3f13c9444422f0cd9d", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/applicationCommandOption.ts": "4a8f10906d292a12c9aa22c144b0f54b1ad46e5e36f1bbb9f2c897b2a4ab3fdd", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/applicationCommandOptionChoice.ts": "f6f45eebe9964acb3183ab94c05c20710f25524d88e4cec5b8a39e39477c3cfe", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/applicationCommandPermission.ts": "fbccf9f08b5c0191c3066e1aff3d7b2ba52ff141a492b76a4bcc5a081cc2bb8e", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/attachment.ts": "80c839a176cfe5850eee76f935c5ecac63093ab98b527539a8b15f76023adf7d", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/auditLogEntry.ts": "f534162a5ead7f2af0a7dff10ebc62783fa2c2bb75f80e9f55eea2d7614445ba", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/component.ts": "fff5d9b50ee04070c5155be4d66ae1dcd40cd6d22c80e1d31511d81e2dacb9e4", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/createApplicationCommand.ts": "3cd6b1450dea84031a10544a577c69830683e81b7c16c759b560b2ced3b5839f", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/embed.ts": "3f670eed57d512104888a55b9d7f4b213b32d8624d992cc5a30bcbd656046d2e", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/emoji.ts": "5aa260f373d748206a1f56ed61530af9f8ddd761660b303f8c9e9adf64707ec8", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/gatewayBot.ts": "8ae9a6a7c432f3485206e0ccb50e114cfbf3ca7789a60a01c660139ce499c8a8", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/interactionResponse.ts": "2a2dae0e50d160e632c935473344d90beb8f8fe7ffddd3c1c18dde78f14f2ec8", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/member.ts": "81f2450b4d5c326988773d07271757c0be615e325de1564d1fd0519c3f8bb820", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/mod.ts": "ae8ba055d871c3c3c423d34ea7cec0a4e9a328f7d5666eb18774c256627440ef", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/presence.ts": "4a6a0cfd7b5e7012d735ce50ba3a307bc4be1886348cf32a54bf6abc0ce23cf5", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/team.ts": "e2b584c75d08259ac967a37ba70157e0e67a666f3f1e2a640168288335f56b7e", + "https://deno.land/x/discordeno@18.0.0/transformers/reverse/widgetSettings.ts": "69142807adba5bcdc11fc75371e6137265f8dd8150bd0b6edf74aa7c43b9beba", + "https://deno.land/x/discordeno@18.0.0/transformers/role.ts": "22b009e642da7a4ce60e2d7ecc2d1a9dbf9b2a62c4157e11e9ad47bd317bc1a2", + "https://deno.land/x/discordeno@18.0.0/transformers/scheduledEvent.ts": "d42a5705128c09c4d7ba9553aefb720b5dde45530d1321351952f1bb7e9c7fe7", + "https://deno.land/x/discordeno@18.0.0/transformers/stageInstance.ts": "32feef2844d958f0b2d72a35b78b9ec1d0898b7c8eae6f4376327634cf7b4a1f", + "https://deno.land/x/discordeno@18.0.0/transformers/sticker.ts": "b8395b490610d113e9bfd2697aaad1ed4c80862937aa894b7bc1a1edeef4dd1c", + "https://deno.land/x/discordeno@18.0.0/transformers/team.ts": "bae401ece7629270b3d08699b7a50a948ee30874e7b3b53cf415af5802780ec0", + "https://deno.land/x/discordeno@18.0.0/transformers/template.ts": "f0bc99775bd27d83145c8a245e2b5b5d2c2095179eb1ef3c1bca21ff012f0f75", + "https://deno.land/x/discordeno@18.0.0/transformers/threadMember.ts": "698ba17d1bdcc927b83f373a0a9ea666623b9560a0009f0c366f17c4e10c92f5", + "https://deno.land/x/discordeno@18.0.0/transformers/toggles/ToggleBitfield.ts": "5192c9636cd9d6295970e357d40d00696d0cadca290db2ae052109fbc7f34294", + "https://deno.land/x/discordeno@18.0.0/transformers/toggles/emoji.ts": "c87f5ee9e6ce5765f4d9c4413ec8c38f427abc7b61ca33347b240749ad13fec8", + "https://deno.land/x/discordeno@18.0.0/transformers/toggles/guild.ts": "fdc7ef617f8585b4f8e0cd1af8701c6f6800c204834f0869a11c63242206cd09", + "https://deno.land/x/discordeno@18.0.0/transformers/toggles/member.ts": "10621e31e24371a05fa663e6367f87484d98a8df1b477f42607565c7ecc74cae", + "https://deno.land/x/discordeno@18.0.0/transformers/toggles/mod.ts": "258db99ff582782ce080648b7fe99b98addd535926d30b07846f1328711d178e", + "https://deno.land/x/discordeno@18.0.0/transformers/toggles/role.ts": "2003bbf8fb4d2c2a05f199f6dddf2f226710056f73589645de5b87cd9140a4ae", + "https://deno.land/x/discordeno@18.0.0/transformers/toggles/user.ts": "56d99df1676757790a9a98d26ffa6e2ef329b59044211ef95f4fd309fd0ba172", + "https://deno.land/x/discordeno@18.0.0/transformers/toggles/voice.ts": "60afbfe8ae9b4c2f8903720792fcbd9354181d4764a7035ab2437398a4deabfc", + "https://deno.land/x/discordeno@18.0.0/transformers/voiceRegion.ts": "a2aafa0e6e8b5f93e872ed6ae9d39422612f05ee827735a8b67518dbe0aae33b", + "https://deno.land/x/discordeno@18.0.0/transformers/voiceState.ts": "8bcd18fbf5ac3f4c74d7e5a8fefc9a8387e20ef653933dd75789b1030a67dba1", + "https://deno.land/x/discordeno@18.0.0/transformers/webhook.ts": "554d5067bb062c2e3b7acd695524ad1623f718ec018b12e24baa19780d546750", + "https://deno.land/x/discordeno@18.0.0/transformers/welcomeScreen.ts": "752fd62e3fd02661731da8e99748dfa070ea47b40fcf60a99edcde0150c799d1", + "https://deno.land/x/discordeno@18.0.0/transformers/widget.ts": "4ac5d91e08397d02c0122864499e7b787b8a021aa188e6c33ea7049adbf2025c", + "https://deno.land/x/discordeno@18.0.0/transformers/widgetSettings.ts": "f6b18308e30225ff52fb685421e3fa3fee26e5cb08dfa937979221f8ecf54bb3", + "https://deno.land/x/discordeno@18.0.0/types/discord.ts": "9eff1f4aef5baedf3542d3fb8580b41ab56868a00cb64d621db901c477d85ba6", + "https://deno.land/x/discordeno@18.0.0/types/discordeno.ts": "678d939172542efe770d6426b89419c9a0bda5185f0dbae1802378ae741ccfc3", + "https://deno.land/x/discordeno@18.0.0/types/mod.ts": "fe28c2252f98d3e699be672a0503e5829ac03c22bcf28d50f5ea11ccbcb21e5e", + "https://deno.land/x/discordeno@18.0.0/types/shared.ts": "fea0ac588e04e76309277ba8c7e5e1918249bc7f4c48d773b65cae36df82611e", + "https://deno.land/x/discordeno@18.0.0/util/base64.ts": "d8d1e2aece75aeaf38edb0169f44024a8c3d2acdea93eb7994e11e9138648c1d", + "https://deno.land/x/discordeno@18.0.0/util/bigint.ts": "5f516ad9023401eb984b56b6fbf56ab4bc2bad881ce58200963992bb99812659", + "https://deno.land/x/discordeno@18.0.0/util/bucket.ts": "86247c46a217eafe421ae3cb0a964d82136306f11031693ab72296f287c7a0fd", + "https://deno.land/x/discordeno@18.0.0/util/calculateShardId.ts": "897f63e613124c2f2aba77f9c909fe5e27f3a29759c813e39050e7945fce3e7a", + "https://deno.land/x/discordeno@18.0.0/util/collection.ts": "3ac580f642568416d74b70ae060f30a660aaf072c851e7fc59aadf8d6381d98b", + "https://deno.land/x/discordeno@18.0.0/util/constants.ts": "5f9d26e10b107035a494982f3232deaac86e2fb2d12410645e705a5015309526", + "https://deno.land/x/discordeno@18.0.0/util/hash.ts": "23047c82bc271fb9ecf4744f37ac68adfbd97a910bee193e45987e4868a57db8", + "https://deno.land/x/discordeno@18.0.0/util/mod.ts": "066f668d4bfa07110c8de4f671de881d87242e05608982c863d7dc5b60d67a25", + "https://deno.land/x/discordeno@18.0.0/util/permissions.ts": "24af940cfecdc19931f1440ca1c9f4a3d4581129a80385d873018fb5ca4f4bb6", + "https://deno.land/x/discordeno@18.0.0/util/routes.ts": "c322be8cd13fddc5d7d89d994f32c655aa752651ad8fdbe7528e53334e0addc5", + "https://deno.land/x/discordeno@18.0.0/util/token.ts": "4b5f415ee8a462866c35d60551e7cdc361ad88172d63d124e5722f61e0e03c08", + "https://deno.land/x/discordeno@18.0.0/util/urlToBase64.ts": "8fcb7373327e151883bddb28baf9581044402fabaa548230e12ec35611e6a204", + "https://deno.land/x/discordeno@18.0.0/util/utils.ts": "b16797ea1918af635f0c04c345a7c9b57c078310ac18d0c86936ec8abfaeddeb", + "https://deno.land/x/discordeno@18.0.0/util/validateLength.ts": "7c610911d72082f9cfe2c455737cd37d8ce8f323483f0ef65fdfea6a993984b5", + "https://deno.land/x/discordeno@18.0.0/util/verifySignature.ts": "8ba1c3d2698f347b4f32a76bd33edeb67ee9d23c34f419a797c393926786bb97", + "https://denopkg.com/burhanahmeed/time.ts@v2.0.1/lib/new-api.ts": "eb5ea9896fb54ff1a7d5fdd90446e3302d130cf6ee02d5132dd62c2dd4320713", + "https://denopkg.com/burhanahmeed/time.ts@v2.0.1/lib/time.ts": "b44f0471340af96d86799b63348ae86318f09104b7d1a13ad5f9b9db72afb174", + "https://denopkg.com/burhanahmeed/time.ts@v2.0.1/lib/timezone.ts": "7a228ddf5a80b8df7fb08a543f095631d9850be086ef783cf46984b40623b14f", + "https://denopkg.com/burhanahmeed/time.ts@v2.0.1/lib/type.ts": "272b84228582febfea09d9de64ef2b0f9b87668f7bbe5f8b655698a37a76f935", + "https://denopkg.com/burhanahmeed/time.ts@v2.0.1/mod.ts": "4cdaa33f88584fd832d57e9a9c1817ebf6bc9770d7d021d8c874902a4205a196", + "https://unpkg.com/@evan/wasm@0.0.93/target/ed25519/deno.js": "9728126890f17b71cee41afdab8a4bc362f6b9f409fe0a5c4f6ca9f3b510fd3a", + "https://unpkg.com/@evan/wasm@0.0.94/target/zlib/deno.js": "e65131e1c1f45e64960f2699a0b868927ea5c9201c4b986a7cfc57b18be5cc09" + } +} diff --git a/discord/discord.ts b/discord/discord.ts deleted file mode 100644 index 48593c4b..00000000 --- a/discord/discord.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { - createBot, - startBot, - Bot, - BotWithCache, - enableCachePlugin, - enableCacheSweepers, - EventDispatcher, - InteractionDispatcher -} from "./mod.ts"; -import { Logger } from "../logging/logger.ts"; - -export interface DiscordInitOpts { - token: string; - intents: number; - botId: bigint|number; - withCache?: boolean; - withSweeper?: boolean; -} - -export class Discord { - protected static bot: Bot|BotWithCache|undefined; - protected token = ''; - protected intents: number; - protected botId = BigInt(0); - - /** - * Return the instance of the Discord bot connection - */ - public static getBot(): Bot|BotWithCache { - if(!Discord.bot) throw new Error('Bot was not properly initialized!'); - return Discord.bot; - } - - public constructor(opts: DiscordInitOpts) { - // Make sure required parameters are present - if('token' in opts) { - this.token = opts.token; - } else { - Logger.error('No Discord bot token was provided!'); - Deno.exit(1); - } - this.intents = 'intents' in opts ? opts.intents : 0; - if('botId' in opts) this.botId = BigInt(opts.botId); - - const baseBot = createBot({ - token: this.token, - intents: this.intents, - botId: this.botId, - events: { - botUpdate(_bot, user) { - EventDispatcher.dispatch('BotUpdate', user); - }, - channelCreate(_bot, channel) { - EventDispatcher.dispatch('ChannelCreate', channel); - }, - channelDelete(_bot, channel) { - EventDispatcher.dispatch('ChannelDelete', channel); - }, - channelPinsUpdate(_bot, data) { - EventDispatcher.dispatch('ChannelPinsUpdate', data); - }, - channelUpdate(_bot, channel) { - EventDispatcher.dispatch('ChannelUpdate', channel); - }, - // deno-lint-ignore no-explicit-any -- Set by Discordeno - debug(text, ...args: any[]) { - EventDispatcher.dispatch('Debug', { text: text, args: args }); - }, - dispatchRequirements(_bot, data, shardId) { - EventDispatcher.dispatch('DispatchRequirements', { data: data, shardId: shardId }); - }, - guildBanAdd(_bot, user, guildId) { - EventDispatcher.dispatch('GuildBanAdd', { user: user, guildId: guildId }); - }, - guildBanRemove(_bot, user, guildId) { - EventDispatcher.dispatch('GuildBanRemove', { user: user, guildId: guildId }); - }, - guildCreate(_bot, guild) { - EventDispatcher.dispatch('GuildCreate', guild); - }, - guildDelete(_bot, id, shardId) { - EventDispatcher.dispatch('GuildDelete', { id: id, shardId: shardId }); - }, - guildEmojisUpdate(_bot, payload) { - EventDispatcher.dispatch('guildEmojisUpdate', payload); - }, - guildMemberAdd(_bot, member, user) { - EventDispatcher.dispatch('GuildMemberAdd', { member: member, user: user }); - }, - guildMemberRemove(_bot, user) { - EventDispatcher.dispatch('GuildMemberRemove', user); - }, - guildMemberUpdate(_bot, member, user) { - EventDispatcher.dispatch('GuildMemberUpdate', { member: member, user: user }); - }, - guildUpdate(_bot, guild) { - EventDispatcher.dispatch('GuildUpdate', guild); - }, - integrationCreate(_bot, integration) { - EventDispatcher.dispatch('IntegrationCreate', integration); - }, - integrationDelete(_bot, payload) { - EventDispatcher.dispatch('IntegrationDelete', payload); - }, - integrationUpdate(_bot, payload) { - EventDispatcher.dispatch('IntegrationUpdate', payload); - }, - interactionCreate(_bot, interaction) { - EventDispatcher.dispatch('InteractionCreate', interaction); - }, - inviteCreate(_bot, invite) { - EventDispatcher.dispatch('InviteCreate', invite); - }, - inviteDelete(_bot, payload) { - EventDispatcher.dispatch('InviteDelete', payload); - }, - messageCreate(_bot, message) { - // Remapped to "MessageReceive" - // Reason: Easier to understand - EventDispatcher.dispatch('MessageReceive', { message: message }); - }, - messageDelete(_bot, payload, message?) { - EventDispatcher.dispatch('MessageDelete', { payload: payload, message: message }); - }, - messageUpdate(_bot, message, oldMessage?) { - EventDispatcher.dispatch('MessageUpdate', { message: message, oldMessage: oldMessage }); - }, - presenceUpdate(_bot, presence, oldPresence?) { - EventDispatcher.dispatch('PresenceUpdate', { presence: presence, oldPresence: oldPresence }); - }, - raw(_bot, data, shardId) { - EventDispatcher.dispatch('Raw', { data: data, shardId: shardId }); - }, - reactionAdd(_bot, payload) { - // Remapped to "MessageReactionAdd" - // Reason: Easier to understand - EventDispatcher.dispatch('MessageReactionAdd', payload); - }, - reactionRemove(_bot, data) { - // Remapped to "MessageReactionRemove" - // Reason: Easier to understand - EventDispatcher.dispatch('MessageReactionRemove', data); - }, - reactionRemoveAll(_bot, payload) { - // Remapped to "MessageReactionRemoveAll" - // Reason: Easier to understand - EventDispatcher.dispatch('MessageReactionRemoveAll', payload); - }, - reactionRemoveEmoji(_bot, payload) { - EventDispatcher.dispatch('ReactionRemoveEmoji', payload); - }, - ready(_bot, payload, rawPayload) { - // Remapped to "BotReady" - // Reason: Easier to understand - EventDispatcher.dispatch('BotReady', { payload: payload, rawPayload: rawPayload }); - }, - roleCreate(_bot, role) { - EventDispatcher.dispatch('RoleCreate', role); - }, - roleDelete(_bot, role) { - EventDispatcher.dispatch('RoleDelete', role); - }, - roleUpdate(_bot, role) { - EventDispatcher.dispatch('RoleUpdate', role); - }, - scheduledEventCreate(_bot, event) { - EventDispatcher.dispatch('ScheduledEventCreate', event); - }, - scheduledEventDelete(_bot,event) { - EventDispatcher.dispatch('ScheduledEventDelete', event); - }, - scheduledEventUpdate(_bot,event) { - EventDispatcher.dispatch('ScheduledEventUpdate', event); - }, - scheduledEventUserAdd(_bot, payload) { - EventDispatcher.dispatch('ScheduledEventUserAdd', payload); - }, - scheduledEventUserRemove(_bot, payload) { - EventDispatcher.dispatch('ScheduledEventUserRemove', payload); - }, - stageInstanceCreate(_bot, data) { - EventDispatcher.dispatch('StageInstanceCreate', data); - }, - stageInstanceDelete(_bot, data) { - EventDispatcher.dispatch('StageInstanceDelete', data); - }, - stageInstanceUpdate(_bot, data) { - EventDispatcher.dispatch('StageInstanceUpdate', data); - }, - threadCreate(_bot, thread) { - EventDispatcher.dispatch('ThreadCreate', thread); - }, - threadDelete(_bot, thread) { - EventDispatcher.dispatch('ThreadDelete', thread); - }, - threadMembersUpdate(_bot, payload) { - EventDispatcher.dispatch('ThreadMembersUpdate', payload); - }, - threadUpdate(_bot, thread) { - EventDispatcher.dispatch('ThreadUpdate', thread); - }, - typingStart(_bot, payload) { - EventDispatcher.dispatch('TypingStart', payload); - }, - voiceServerUpdate(_bot, payload) { - EventDispatcher.dispatch('VoiceServerUpdate', payload); - }, - voiceStateUpdate(_bot, voiceState) { - EventDispatcher.dispatch('VoiceStateUpdate', voiceState); - }, - webhooksUpdate(_bot, payload) { - EventDispatcher.dispatch('WebhooksUpdate', payload); - }, - } - }); - - // Enable cache if required - Discord.bot = Discord.enableCache(baseBot, opts); - } - - /** - * Start the bot and connect to the Discord gateway - * - * @returns Promise - */ - public async start(): Promise { - if(!Discord.bot) throw Error('Bot is not configured!'); - await EventDispatcher.load(); - await InteractionDispatcher.load(); - await startBot(Discord.bot); - } - - /** - * Checks whether cache needs to be enabled. - * Add both cache and sweeper if required. - * - * @param bot - * @param opts - */ - private static enableCache(bot: Bot, opts: DiscordInitOpts): Bot|BotWithCache { - // Return the bot if no cache needs to be enabled - // Otherwise enable the cache - if (!opts.withCache) return bot; - bot = enableCachePlugin(bot); - - // Return the bot if no sweeper needs to be enabled - // Otherwise enable the sweeper and return the final bot - if(!opts.withSweeper) return bot; - enableCacheSweepers(bot as BotWithCache); - return bot; - } -} diff --git a/discord/event/dispatcher.ts b/discord/event/dispatcher.ts deleted file mode 100644 index d3cbf238..00000000 --- a/discord/event/dispatcher.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { Logger } from "../../logging/logger.ts"; -import { Folder } from "../../filesystem/folder.ts"; -import { File } from "../../filesystem/file.ts"; -import { Inflector } from "../../utility/inflector.ts"; - -interface EventConfig { - name: string; - handler: string; -} - -export class EventDispatcher { - private static list: EventConfig[] = []; - // deno-lint-ignore no-explicit-any -- TODO - private static handlers: any = {}; - - /** - * Return the complete list of events - * - * @returns EventConfig[] - */ - public static getEvents(): EventConfig[] { return EventDispatcher.list; } - - /** - * Find an Event by name - * - * @param name - * @returns EvenConfig|undefined - */ - public static getHandler(name: string): EventConfig|undefined { - return EventDispatcher.list.find((event: EventConfig) => event.name === name); - } - - /** - * Import an event handler and add it to the list of handlers - * TODO: Make sure class implements Event - * - * @param event - * @returns Promise - */ - public static async add(event: EventConfig): Promise { - try { - // Import the source file - const handler = await import(`file://${Deno.cwd()}/src/events/${event.handler}.ts`); - - // Make sure source file has required class - if(!(`${event.name}Event` in handler)) throw Error(`No class named "${event.name}Event" could be found!`); - - // Register handler - EventDispatcher.handlers[event.handler] = handler; - } catch(e) { - Logger.error(`Could not register event handler for "${event.name}": ${e.message}`, e.stack); - return; - } - - EventDispatcher.list.push(event); - } - - /** - * Run an instance of the Feature handler - * - * @param event - * @param data - * @returns Promise - */ - // deno-lint-ignore no-explicit-any -- TODO - public static async dispatch(event: string, data: any = {}): Promise { - // Get the event handler - const handler = EventDispatcher.getHandler(event); - if(!handler) return Logger.debug(`Event "${event}" does not exist! (did you register it?)`); - - // Create an instance of the event handler - const controller = new EventDispatcher.handlers[handler.handler][`${event}Event`](data); - - // Execute the handler's execute method - try { - await controller['execute'](data); - } catch(e) { - Logger.error(`Could not dispatch event "${event}": "${e.message}"`, e.stack); - } - } - - /** - * Load all events from the required directory. - * By convention, this will be "src/events". - */ - public static async load(): Promise { - // Create our directory string - const dir = `${Deno.cwd()}/src/events`; - Logger.debug(`Loading events from "${dir}"...`); - - // Make sure the interactions directory exists - if(!await new Folder(dir).exists()) { - Logger.warning(`"${dir}" does not exist, no events to load.`); - return; - } - - // Get a list of all files - const files = await Deno.readDir(dir); - - // Load all interactions - const promiseQueue: Promise[] = []; - for await(const file of files) { - if(new File(`${dir}/${file.name}`).ext() === '.ts') { - Logger.debug(`File "${file.name}" is not a TS file, skipping...`); - continue; - } - - // Import the file as a module - Logger.debug(`Loading "${file.name}"...`); - const module = await import(`file:///${dir}/${file.name}`); - - // Make sure the file contains a valid handler - const name = file.name.replace('.ts', ''); - const eventName = Inflector.pascalize(name, '-'); - const className = `${eventName}Event`; - if(!(className in module)) { - Logger.warning(`Could not find ${className} in "${file.name}", skipping...`); - continue; - } - - // Register in the dispatcher - promiseQueue.push( - EventDispatcher.add({ - name: eventName, - handler: name, - }) - ); - } - - // Wait until the promise queue has cleared - await Promise.all(promiseQueue); - } -} diff --git a/discord/event/event.ts b/discord/event/event.ts deleted file mode 100644 index 7139a80b..00000000 --- a/discord/event/event.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Event { - execute(opts: unknown): Promise; -} diff --git a/discord/interaction/builder.ts b/discord/interaction/builder.ts deleted file mode 100644 index b34c3b3e..00000000 --- a/discord/interaction/builder.ts +++ /dev/null @@ -1,164 +0,0 @@ -import {ApplicationCommandOptionTypes, ApplicationCommandTypes} from "../mod.ts"; - -type OptionTypes = - | ((command: InteractionSubcommandBuilder) => void) - | ((option: InteractionOptionBuilder) => void) - -type CommandTypes = keyof typeof ApplicationCommandTypes; -type CommandOptionTypes = keyof typeof ApplicationCommandOptionTypes; - -export class InteractionBuilder { - private _name: string = undefined!; - private _description: string = undefined!; - private _type: ApplicationCommandTypes = ApplicationCommandTypes.ChatInput; - private _options: Array = []; - - public setName(name: string): InteractionBuilder { - this._name = name; - - return this; - } - - public setDescription(description: string): InteractionBuilder { - this._description = description; - - return this; - } - - public setType(type: CommandTypes): InteractionBuilder { - this._type = ApplicationCommandTypes[type]; - - return this; - } - - public addSubcommand(command: (command: InteractionSubcommandBuilder) => InteractionSubcommandBuilder): InteractionBuilder { - // @ts-ignore TODO: Figure out why this throws an error during tests - this._options.push(command(new InteractionSubcommandBuilder())); - - return this; - } - - public addOption(option: (option: InteractionOptionBuilder) => void): InteractionBuilder { - // @ts-ignore TODO: Figure out why this throws an error during tests - this._options.push(option(new InteractionOptionBuilder())); - - return this; - } - - public toJSON() { - // Create object for our interaction - const data = { - name: this._name, - description: this._description, - type: this._type, - options: [] - }; - - // Add data for our options - for(const option of this._options) { - // @ts-ignore TODO: Figure out why this throws an error during tests - data.options.push(option.toJSON()); - } - - return data; - } -} - -export class InteractionSubcommandBuilder { - protected _name: string = undefined!; - protected _description: string = undefined!; - private _type: ApplicationCommandOptionTypes = ApplicationCommandOptionTypes.SubCommand; - protected _options: Array = []; - - public setName(name: string): InteractionSubcommandBuilder { - this._name = name; - - return this; - } - - public setDescription(description: string): InteractionSubcommandBuilder { - this._description = description; - - return this; - } - - public setType(type: CommandOptionTypes): InteractionSubcommandBuilder { - this._type = ApplicationCommandOptionTypes[type]; - - return this; - } - - public addOption(option: (option: InteractionOptionBuilder) => void): InteractionSubcommandBuilder { - // @ts-ignore TODO: Figure out why this throws an error during tests - this._options.push(option(new InteractionOptionBuilder())); - - return this; - } - - public toJSON() { - // Create object for our subcommand - const data = { - name: this._name, - description: this._description, - type: this._type, - options: [] - }; - - // Add data for our options - for(const option of this._options) { - // @ts-ignore TODO: Figure out why this throws an error during tests - data.options.push(option.toJSON()); - } - - return data; - } -} - -export class InteractionOptionBuilder { - private _name: string = undefined!; - private _description: string = undefined!; - private _required = false; - private _autocomplete: boolean = false; - private _type: ApplicationCommandOptionTypes = undefined!; - - public setName(name: string): InteractionOptionBuilder { - this._name = name; - - return this; - } - - public setDescription(description: string): InteractionOptionBuilder { - this._description = description; - - return this; - } - - public setType(type: CommandOptionTypes): InteractionOptionBuilder { - this._type = ApplicationCommandOptionTypes[type]; - - return this; - } - - public setRequired(required: boolean): InteractionOptionBuilder { - this._required = required; - - return this; - } - - public setAutocomplete(autocomplete: boolean): InteractionOptionBuilder { - this._autocomplete = autocomplete; - - return this; - } - - public toJSON() { - // Create object for our option - return { - name: this._name, - description: this._description, - type: this._type, - required: this._required, - autocomplete: this._autocomplete, - }; - } -} diff --git a/discord/interaction/dispatcher.ts b/discord/interaction/dispatcher.ts deleted file mode 100644 index 6138a0e2..00000000 --- a/discord/interaction/dispatcher.ts +++ /dev/null @@ -1,160 +0,0 @@ -import {ApplicationCommandOption, ApplicationCommandTypes, BigString, DiscordInteraction} from "../mod.ts"; -import { Discord } from "../discord.ts"; -import { Logger } from "../../logging/logger.ts"; -import { File } from "../../filesystem/file.ts"; -import { Folder } from "../../filesystem/folder.ts"; -import { Inflector } from "../../utility/inflector.ts"; -import { InteractionBuilder } from "./builder.ts"; - -export interface InteractionConfig { - name: string; - description: string; - type: ApplicationCommandTypes; - options?: ApplicationCommandOption[]; - handler: string; -} - -export class InteractionDispatcher { - private static _interactionsDir = `${Deno.cwd()}/src/interactions`; - private static list: InteractionConfig[] = []; - // deno-lint-ignore no-explicit-any -- TODO - private static handlers: any = {}; - - /** - * Return the complete list of interactions - * - * @returns IInteraction[] - */ - public static getInteractions() { return InteractionDispatcher.list; } - - /** - * Find an Interaction by name - * - * @param name - * @returns InteractionConfig|undefined - */ - public static getHandler(name: string): InteractionConfig|undefined { - return InteractionDispatcher.list.find((interaction: InteractionConfig) => interaction.name === name); - } - - /** - * Update all interactions registered to the Discord gateway - * - * @param opts - * @returns Promise - */ - public static async update(opts: {guildId: bigint|BigString}): Promise { - try { - await Discord.getBot()?.helpers.upsertGuildApplicationCommands(opts.guildId.toString(), InteractionDispatcher.getInteractions()); - } catch(e) { - Logger.error(`Could not update interactions: ${e.message}`); - } - } - - /** - * Import an interaction handler and add it to the list of handlers - * - * @param interaction - * @returns Promise - */ - public static async add(interaction: InteractionConfig): Promise { - try { - // Import the interaction handler - InteractionDispatcher.handlers[interaction.handler] = await import(`file://${InteractionDispatcher._interactionsDir}/${interaction.handler}.ts`) - } catch(e) { - Logger.error(`Could not register interaction handler for "${interaction}": ${e.message}`); - return; - } - - InteractionDispatcher.list.push(interaction); - } - - /** - * Run an instance of the Interaction handler - * - * @param interaction - * @param data - * @returns Promise - */ - public static async dispatch(interaction: string, data: DiscordInteraction): Promise { - // Get the handler - const handler = InteractionDispatcher.getHandler(interaction); - if(!handler) { - Logger.debug(`Interaction "${interaction}" does not exist! (did you register it?)`); - return; - } - - // Create an instance of the handler - const controller = new InteractionDispatcher.handlers[handler.handler][`${Inflector.pascalize(interaction)}Interaction`](data); - - // Execute the handler's execute method - await controller['execute'](); - } - - /** - * Load all interactions from the required directory. - * By convention, this will be "src/interactions". - */ - public static async load(): Promise { - // Create our directory string - Logger.debug(`Loading interactions from "${InteractionDispatcher._interactionsDir}"...`); - - // Make sure the interactions directory exists - if(!await new Folder(InteractionDispatcher._interactionsDir).exists()) { - Logger.warning(`"${InteractionDispatcher._interactionsDir}" does not exist, no interactions to load`); - return; - } - - // Get a list of all files - const files = await Deno.readDir(InteractionDispatcher._interactionsDir); - - // Load all interactions - const promiseQueue: Promise[] = []; - for await(const file of files) { - if(new File(`${InteractionDispatcher._interactionsDir}/${file.name}`).ext() === '.ts') { - Logger.debug(`File "${file.name}" is not a TS file, skipping...`); - continue; - } - - // Import each file as a module - Logger.debug(`Loading "${file.name}"...`); - const module = await import(`file:///${InteractionDispatcher._interactionsDir}/${file.name}`); - - // Get the interaction name - let name = file.name.replace(".ts", ""); - name = Inflector.pascalize(name); - - // Check if the module contains the interaction class - if(!(`${name}Interaction` in module)) { - Logger.warning(`Could not find "${name}Interaction" in "${file.name}"...`); - continue; - } - - // Make sure module has a "config" exposed - if(!('config' in module)) { - Logger.warning(`Could not find config in "${name}Interaction", skipping...`); - continue; - } - - // Register in dispatcher - // TODO: Remove support for registering as object. - switch(typeof module.config) { - case 'object': { - Logger.warning(`Registering module configs as objects is deprecated. Please use the "InteractionBuilder" instead.`); - module.config['handler'] = module.config.name; - promiseQueue.push(InteractionDispatcher.add(module.config)); - break; - } - case 'function': { - const config = module.config(new InteractionBuilder()).toJSON(); - config['handler'] = config.name; - promiseQueue.push(InteractionDispatcher.add(config)); - break; - } - } - } - - // Wait until the promise queue has cleared - await Promise.all(promiseQueue); - } -} diff --git a/discord/interaction/interaction.ts b/discord/interaction/interaction.ts deleted file mode 100644 index ac56230f..00000000 --- a/discord/interaction/interaction.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {Discord, DiscordInteraction, InteractionCallbackData, InteractionResponse} from "../mod.ts"; - -export class Interaction { - protected interaction: DiscordInteraction; - private _hasReplied: boolean = false; - - public constructor(opts: {interaction: DiscordInteraction}) { - this.interaction = opts.interaction; - } - - /** - * Main logic for the interaction. - * - * @returns Promise - */ - public async execute?(): Promise; - - /** - * Respond to the interaction. - * This method will automatically edit the original reply if already replied. - * - * @param data - */ - protected async respond(data: InteractionResponse|InteractionCallbackData): Promise { - if(!this._hasReplied) { - await Discord.getBot().helpers.sendInteractionResponse( - this.interaction.id, - this.interaction.token, - data as InteractionResponse - ); - this._hasReplied = true; - return; - } - - await Discord.getBot().helpers.editOriginalInteractionResponse( - this.interaction.token, - data as InteractionCallbackData - ); - } -} diff --git a/discord/mod.ts b/discord/mod.ts deleted file mode 100644 index e5e40865..00000000 --- a/discord/mod.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Export Discordeno -export * from "https://deno.land/x/discordeno@18.0.0/mod.ts"; -export { enableCachePlugin, enableCacheSweepers } from "https://deno.land/x/discordeno@18.0.0/plugins/cache/mod.ts"; -export type { BotWithCache } from "https://deno.land/x/discordeno@18.0.0/plugins/cache/mod.ts"; - -// Export EventDispatcher -export { EventDispatcher } from "./event/dispatcher.ts"; -export type { Event } from "./event/event.ts"; - -// Export InteractionDispatcher -export * from "./interaction/builder.ts"; -export * from "./interaction/dispatcher.ts"; -export type { InteractionConfig } from "./interaction/dispatcher.ts"; -export { Interaction } from "./interaction/interaction.ts"; - -// Export Utility functions -export { findChannelByName } from "./util/find-channel-by-name.ts"; -export { findRoleByName } from "./util/find-role-by-name.ts"; -export { snowflakeToDate } from "./util/snowflake-to-date.ts"; - -// Export Discord class -export { Discord } from "./discord.ts"; - -// Export Constants -export const DISCORD_EPOCH: number = 1_420_070_400_000; diff --git a/discord/util/find-channel-by-name.ts b/discord/util/find-channel-by-name.ts deleted file mode 100644 index 6bc0d927..00000000 --- a/discord/util/find-channel-by-name.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Discord, Channel } from "../mod.ts"; -import { Logger } from "../../logging/logger.ts"; - -/** - * Find a channel by its name rather than ID - * TODO: (1) Create a Map that maps channel names and snowflakes together (updates on event by gateway) - * TODO: (2) Lookup channel name in new map (acts as cache) - * TODO: (3) Obtain channel from channels list directly - * - * @param guild - * @param name - */ -export async function findChannelByName(guild: bigint, name: string): Promise { - const channels = await Discord.getBot().helpers.getChannels(guild.toString()); - if(!channels) { - Logger.error(`Could not obtain channels for guild! (this is a bug!)`); - return null; - } - - const channel = channels.find((channel: Channel) => channel.name === name.toLowerCase()); - if(!channel) { - Logger.error(`No channel with name "#${name}" could be found! (did you set it up yet?)`); - return null; - } - - return channel; -} diff --git a/discord/util/find-role-by-name.ts b/discord/util/find-role-by-name.ts deleted file mode 100644 index db98921f..00000000 --- a/discord/util/find-role-by-name.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Cache } from "../../core/cache.ts"; -import { Discord, Role } from "../mod.ts"; -import { Logger } from "../../logging/logger.ts"; -import empty from "../../utility/empty.ts"; - -/** - * Find a role by its name rather than ID - * - * @param guild - * @param roleName - * @param expiry Expiry time. Pass null to disable caching. - * @returns Promise - */ -export async function findRoleByName(guild: bigint, roleName: string, expiry: string|null = `+1 hour`): Promise { - if(!empty(expiry) && !Cache.expired(`role name ${roleName}`)) { - return Cache.get(`role name ${roleName}`) as Role; - } - - // Get a list of all roles for the guild - // @ts-ignore Using null-coalescing to check whether cache is enabled - const roles = Discord.getBot().guilds.get(guild)?.roles - ?? await Discord.getBot().helpers.getRoles(guild); - if(!roles) { - Logger.error(`Could not obtain roles for guild! (this is a bug!)`); - return null; - } - - // Find role by name - const role = roles.find((role: Role): boolean => role.name === roleName); - - // Check if a role was found - // Return result - if(!role) { - Logger.error(`No role with name "${roleName}" could be found! (did you set it up yet?)`); - return null; - } - - // Set the cache - if(!empty(expiry)) Cache.set(`role name ${roleName}`, role, expiry); - return role; -} diff --git a/discord/util/snowflake-to-date.ts b/discord/util/snowflake-to-date.ts deleted file mode 100644 index 434236ff..00000000 --- a/discord/util/snowflake-to-date.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { DISCORD_EPOCH } from "../mod.ts"; - -/** - * Turn a Discord snowflake into a date object. - * Source: https://discord.com/developers/docs/reference#snowflake-ids-in-pagination - * - * @param snowflake - * @param epoch - */ -export function snowflakeToDate(snowflake: bigint, epoch: number = DISCORD_EPOCH): Date { - return new Date(Number(snowflake >> 22n) + epoch); -} diff --git a/docs-old/communication/README.md b/docs-old/communication/README.md deleted file mode 100644 index 6ee19085..00000000 --- a/docs-old/communication/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Communication - -Classes that abstract communication with other services. diff --git a/docs-old/communication/druid.md b/docs-old/communication/druid.md deleted file mode 100644 index d9617382..00000000 --- a/docs-old/communication/druid.md +++ /dev/null @@ -1 +0,0 @@ -# Druid diff --git a/docs-old/communication/graphql.md b/docs-old/communication/graphql.md deleted file mode 100644 index 4c81b379..00000000 --- a/docs-old/communication/graphql.md +++ /dev/null @@ -1,7 +0,0 @@ -# GraphQL - -Facilitates querying and mutating GraphQL APIs. - -## Getting Started - -TODO diff --git a/docs-old/communication/influxdb.md b/docs-old/communication/influxdb.md deleted file mode 100644 index 4abe4564..00000000 --- a/docs-old/communication/influxdb.md +++ /dev/null @@ -1 +0,0 @@ -# InfluxDB diff --git a/docs-old/communication/loki.md b/docs-old/communication/loki.md deleted file mode 100644 index 702c5b7a..00000000 --- a/docs-old/communication/loki.md +++ /dev/null @@ -1 +0,0 @@ -# Loki diff --git a/docs-old/communication/ntfy.md b/docs-old/communication/ntfy.md deleted file mode 100644 index 4a856ebf..00000000 --- a/docs-old/communication/ntfy.md +++ /dev/null @@ -1 +0,0 @@ -# Ntfy diff --git a/docs-old/communication/nut.md b/docs-old/communication/nut.md deleted file mode 100644 index 6d2eb3ca..00000000 --- a/docs-old/communication/nut.md +++ /dev/null @@ -1 +0,0 @@ -# NUT diff --git a/docs-old/communication/rcon.md b/docs-old/communication/rcon.md deleted file mode 100644 index b9a977d2..00000000 --- a/docs-old/communication/rcon.md +++ /dev/null @@ -1 +0,0 @@ -# RCON diff --git a/docs-old/communication/redis.md b/docs-old/communication/redis.md deleted file mode 100644 index 51a87de7..00000000 --- a/docs-old/communication/redis.md +++ /dev/null @@ -1 +0,0 @@ -# Redis diff --git a/docs-old/core/README.md b/docs-old/core/README.md deleted file mode 100644 index 3b616f93..00000000 --- a/docs-old/core/README.md +++ /dev/null @@ -1 +0,0 @@ -# Core diff --git a/docs-old/core/cache.md b/docs-old/core/cache.md deleted file mode 100644 index 94502412..00000000 --- a/docs-old/core/cache.md +++ /dev/null @@ -1,87 +0,0 @@ -# Cache - -Facilitates keeping items in memory for a set (or indefinite) period of time. - -## Adding an item to the Cache - -Adding an item to the cache is as simple as calling `Cache.set()`. -By default, items will expire in `1 minute`, however, this can be changed if desired. -```ts -Cache.set('I expire in 1 minute', 'foo'); -Cache.set('I expire in 10 minutes', 'bar', '+10 minutes'); -Cache.set('I never expire', 'baz', null); -``` - -**NOTE**: Expiry times use [TimeString](../utility/time-string.md) formats. - -## Getting an item from the Cache - -You can get items from the cache by calling `Cache.get()`. -```ts -Cache.get('cache item name'); // Honours expiry -Cache.get('cache item name', true); // Optimistically serve expired cache items -``` - -## Checking if an item exists in Cache - -You can check if an item exists in the cache by calling `Cache.exists()`. -However, this does not check whether an item has expired or not so it may exist only if obtained optimistically. -```ts -Cache.exists('cache item name'); -``` - -## Checking if an item has expired - -You can check if an item exists *and* has not yet expired by calling `Cache.expired()`. -Items that have expired *may* still exist but only be able to be obtained optimistically. -```ts -Cache.expired('cache item name'); -``` - -## Remove an item from the Cache - -If you want to remove an item from the cache, you can simply call `Cache.remove()`. -```ts -Cache.remove('cache item name'); -``` - -## Showing all items in Cache - -You can obtain the raw cache contents using the `Cache.dump()` method. -```ts -console.log(Cache.dump()); -``` - -```ts -Map(1) { - "cache item name" => { data: "cache item value", expires: null } -} -``` - -**NOTE**: This should only be done for debugging purposes! - -## Cleaning up expired items - -By default, the cache will be cleaned up every hour. -Items may linger in the cache for up-to an additional hour to enable for more predictable optimistic caching. - -If you want to clean up expired cache items manually, you can do so by running `Cache.sweep()`. -```ts -console.log(Cache.dump()); -Cache.sweep(); -console.log(Cache.dump()); -``` - -```ts -Map(4) { - "entry #1 (expired)" => { data: 1234, expires: 2024-01-25T07:09:04.252Z }, - "entry #2 (expired, optimistic)" => { data: 1234, expires: 2024-01-25T07:20:04.253Z }, - "entry #3 (valid)" => { data: 1234, expires: 2024-01-25T09:20:04.253Z }, - "entry #4 (valid, indefinite)" => { data: 1234, expires: null } -} -Map(3) { - "entry #2 (expired, optimistic)" => { data: 1234, expires: 2024-01-25T07:20:04.253Z }, - "entry #3 (valid)" => { data: 1234, expires: 2024-01-25T09:20:04.253Z }, - "entry #4 (valid, indefinite)" => { data: 1234, expires: null } -} -``` diff --git a/docs-old/core/configure.md b/docs-old/core/configure.md deleted file mode 100644 index 9418fdfe..00000000 --- a/docs-old/core/configure.md +++ /dev/null @@ -1,140 +0,0 @@ -# Configure - -Allows easily setting application configs using JSON rather than environment-variables. - -## Getting Started - -First, create a file `config.json` at your application's root. -By default `debug` and `error_log` are set to these values. -If you want to change them, this is the place where to do it! -```json -{ - "debug": false, - "error_log": "logs/error.logs" -} -``` - -Then import the module as part of Chomp's core and load the configure: -```ts -import * from "https://deno.land/x/chomp/mod.ts"; - -await Configure.load(); -``` - -Although, if you want to use a more minimal setup: -```ts -import { Configure } from "https://deno.land/x/chomp/mod.ts"; - -await Configure.load(); -``` - -## Getting an item from the Configure - -Getting an item from the Configure can be done by calling `Configure.get()`. -Doing this will return either the value set in the configure or `null`. -```ts -const myConst = Configure.get('app configure item'); -``` - -If you want to have a default return value, then you can specify it as follows: -```ts -const myConst = Configure.get('app configure item', 'default value'); -``` - -## Setting or updating an item in the Configure - -Sometimes you may want to set or update an item during runtime. -You can do so as follows: -```ts -Configure.set('app configure item', 'my value'); -``` - -**NOTE**: Changes made here do not persist between restarts of your app. - -## Checking whether an item exists - -To check whether an item exists, just run the following: -```ts -const exists = Configure.check('app configure item'); -``` - -## Consume a Configure item - -Consuming a Configure item will return the item and then remove it. -```ts -const myConst = Configure.consume('app configure item', 'default value'); -``` - -## Delete a Configure item - -Deleting a configure item will remove it from the Configure. - -```ts -Configure.delete('app configure item'); -``` - -**NOTE**: Changes made here do not persist between restarts of your app. - -## Dump all Configure items - -Sometimes it is useful to know all the items that are currently in the Configure. -In this case, you can simply dump all the contents: -```ts -console.log(Configure.dump()); -``` - -```ts -Map(3) { - "debug" => false, - "error_log" => "/path/to/logs/error.log", - "app configuration key" => "app configuration value" -} -``` - -**NOTE**: This should only be done for debugging purposes as it may leak sensitive information! - -## Clear or reset all Configure items - -Made a mistake or have another reason to start with a clean Configure? Then this can be done in two ways: `Configure.clear()` and `Configure.reset()`. - -`Configure.clear()` will *completely* empty the configure: -```ts -console.log(Configure.dump()); -Configure.clear(); -console.log(Configure.dump()); -``` - -```ts -Map(3) { - "debug" => false, - "error_log" => "/path/to/logs/error.log", - "app configuration key" => "app configuration value" -} -Map(0) {} -``` - -Whereas `Configure.clear()` will reset the configure to it's default state: -```ts -console.log(Configure.dump()); -Configure.reset(); -console.log(Configure.dump()); -``` - -```ts -Map(3) { - "debug" => false, - "error_log" => "/path/to/logs/error.log", - "app configuration key" => "app configuration value" -} -Map(2) { - "debug" => false, - "error_log" => "/path/to/logs/error.log" -} -``` - -However, the default state is coded into Chomp itself and is *not* your app's defaults. -If instead, you want to use your app's defaults, you must first clear/reset then force a load: -```ts -Configure.clear(); // Or reset depending on your needs -await Configure.load(true); // Force the configure to reload -``` diff --git a/docs-old/error/README.md b/docs-old/error/README.md deleted file mode 100644 index 8a547396..00000000 --- a/docs-old/error/README.md +++ /dev/null @@ -1 +0,0 @@ -# Error diff --git a/docs-old/error/raise.md b/docs-old/error/raise.md deleted file mode 100644 index 122beb8b..00000000 --- a/docs-old/error/raise.md +++ /dev/null @@ -1,65 +0,0 @@ -# raise - -Utility function that provides a band-aid for ES' shortcoming on not allowing `throw` statements during null-coalescing like, for example, PHP can do. - -```php -// PHP Example -$myVar = null ?? throw new Exception('Error Message'); -``` - -```ts -// TS Example -const myVar = null ?? throw new Error('Error Message'); // Expression expected -``` - -## Getting Started - -First, import the function as follows: -```ts -import { raise } from "https://deno.land/x/chomp/error/raise.ts"; -``` - -Then you can use it in your chains as follows: -```ts -const myVar = null ?? raise('Error Message'); -``` - -## Using Custom Error Types - -By default, the `raise` function will throw a "standard" `Error`: -``` -error: Uncaught (in promise) Error: Error Message -``` - -However, it may be desirable to be able to be more specific in what error has happened: -To do this, you can easily pass a name for the error to `raise`: - -```ts -const myVar = null ?? raise('Error Message', 'CustomError'); -``` -``` -error: Uncaught (in promise) CustomError: Error Message -``` - -Additionally, you can ommit the "Error" part in the name as this will be automatically added: -```ts -const myVar = null ?? raise('Error Message', 'Custom'); -``` -``` -error: Uncaught (in promise) CustomError: Error Message -``` - -If you need more flexibility, you can pass an `Error`-class to `raise` instead: -```ts -class CustomError extends Error { - constructor(public message: string) { - super(message); - } -} - -const myVar = null ?? raise('Error Message', CustomError); -``` - -``` -error: Uncaught (in promise) CustomError: Error Message -``` diff --git a/docs-old/filesystem/README.md b/docs-old/filesystem/README.md deleted file mode 100644 index 6d41ab86..00000000 --- a/docs-old/filesystem/README.md +++ /dev/null @@ -1 +0,0 @@ -# Filesystem diff --git a/docs-old/filesystem/file.md b/docs-old/filesystem/file.md deleted file mode 100644 index 7ac8882e..00000000 --- a/docs-old/filesystem/file.md +++ /dev/null @@ -1 +0,0 @@ -# File diff --git a/docs-old/filesystem/folder.md b/docs-old/filesystem/folder.md deleted file mode 100644 index 658b202c..00000000 --- a/docs-old/filesystem/folder.md +++ /dev/null @@ -1 +0,0 @@ -# Folder diff --git a/docs-old/logging/README.md b/docs-old/logging/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/docs-old/logging/logger.md b/docs-old/logging/logger.md deleted file mode 100644 index 441dd59e..00000000 --- a/docs-old/logging/logger.md +++ /dev/null @@ -1 +0,0 @@ -# Logger diff --git a/docs-old/queue/README.md b/docs-old/queue/README.md deleted file mode 100644 index d095a2b0..00000000 --- a/docs-old/queue/README.md +++ /dev/null @@ -1 +0,0 @@ -# Queue diff --git a/docs-old/utility/README.md b/docs-old/utility/README.md deleted file mode 100644 index e378f07c..00000000 --- a/docs-old/utility/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Utility -General utilities that we didn't see fit under a category just yet. diff --git a/docs-old/utility/check-source.md b/docs-old/utility/check-source.md deleted file mode 100644 index f0fcfe14..00000000 --- a/docs-old/utility/check-source.md +++ /dev/null @@ -1,59 +0,0 @@ -# CheckSource - -CheckSource allows you to run the Deno file checking before hand. -This is useful for helping speed up deployments and reboots as you can now do all the checks in the pipeline rather than while starting the container. - -## Getting Started - -First, import the module as part of Chomp's core: -```ts -import * from "https://deno.land/x/chomp/mod.ts"; -``` - -Or if you want a more minimal setup: -```ts -import { CheckSource } from "https://deno.land/x/chomp/mod.ts"; -``` - -Then add the following code to your check script: -```ts -const checker = new CheckSource('./src'); -await checker.run(); -``` - -Then run the script. -A common way of doing it would be to add a file `check.ts` and running that: - -```ts -// check.ts -import { CheckSource } from "https://deno.land/x/chomp/mod.ts"; - -const checker = new CheckSource('./src'); -await checker.run(); -``` - -``` ->>> deno run --allow-read check.ts -[2024/02/02 23:55:27] INFO > Getting all files in directory "./src"... -[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/controller"... -[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/controller/component"... -[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/events"... -[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/templates"... -[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/templates/anidb"... -[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/templates/database"... -[2024/02/02 23:55:27] INFO > Getting all files in directory "./src/templates/status"... -[2024/02/02 23:55:27] INFO > Checking "15" files... -[2024/02/02 23:55:27] INFO > Finished checking files! -``` - -## Excluding files or directories - -In some cases, you may have additional files or directories mixed into your directory that you may not want to be checked, such as your handlebars templates. -These files and directories can be specified to be ignored very simply by specifying them in the constructor: - -```ts -const checker = new CheckSource('./src', { - directories: ['my-dir'], - files: ['my-file.txt'] -}); -``` diff --git a/docs-old/utility/time-string.md b/docs-old/utility/time-string.md deleted file mode 100644 index 24063fe8..00000000 --- a/docs-old/utility/time-string.md +++ /dev/null @@ -1 +0,0 @@ -# TimeString diff --git a/docs-old/webserver/README.md b/docs-old/webserver/README.md deleted file mode 100644 index a1ca346b..00000000 --- a/docs-old/webserver/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Webserver - -Collection that facilitates easily setting up a webserver. -Adheres to a [CakePHP](https://cakephp.org/)-style Convention-over-Configuration. diff --git a/docs-old/websocket/README.md b/docs-old/websocket/README.md deleted file mode 100644 index a82b3e3c..00000000 --- a/docs-old/websocket/README.md +++ /dev/null @@ -1 +0,0 @@ -# Websocket diff --git a/docs/all_symbols.html b/docs/all_symbols.html new file mode 100644 index 00000000..faf5347c --- /dev/null +++ b/docs/all_symbols.html @@ -0,0 +1,348 @@ + + + + All Symbols - Chomp documentation + + + + + + + + + + + + +

+
+
+
E
+
+ Algorithms + +

List of algorithms supported by this library

+
+
+
c
+
+ Authenticator + +
No documentation available
+
+
c
+
+ Cache + +
No documentation available
+
+
c
+
+ CheckSource + +

Check all files in the specified directories. +Doing this allows the program to start up significantly faster after deployment. +It is NOT a replacement for "deno lint".

+
+
+
c
+
+ Configure + +
No documentation available
+
+
c
+
+ Controller + +
No documentation available
+
+
c
+
+ CouchDB + +
No documentation available
+
+
f
N
+
+ Cron + +

Cron entrypoint

+
+
+
v
+
+ Cron.Cron + +
No documentation available
+
+
v
+
+ DEFAULT_OPTS + +

Default options for password hashing. +These defaults offer a good balance between performance and security.

+
+
+
c
+
+ Druid + +
No documentation available
+
+
E
+
+ ErrorCodes + +
No documentation available
+
+
c
+
+ Events + +
No documentation available
+
+
I
+
+ ExclusionConfig + +
No documentation available
+
+
c
+
+ File + +
No documentation available
+
+
c
+
+ Folder + +
No documentation available
+
+
c
+
+ GraphQL + +
No documentation available
+
+
c
+
+ Hash + +
No documentation available
+
+
c
+
+ Inflector + +

Idea and code primarily based on CakePHP's code.

+
+
+
c
+
+ InfluxDB + +
No documentation available
+
+
v
+
+ INSECURE_ALGORITHMS + +

Specify algorithms that are supported but deemed insecure

+
+
+
c
+
+ Logger + +
No documentation available
+
+
c
+
+ Loki + +
No documentation available
+
+
c
+
+ Ntfy + +
No documentation available
+
+
c
+
+ Nut + +
No documentation available
+
+
c
+
+ Password + +
No documentation available
+
+
v
+
+ PASSWORD_DEFAULT + +

Recommended hashing algorithm for most use-cases. +May change over time to keep up with NIST approved algorithms

+
+
+
I
+
+ PasswordOptions + +

Options for hashing a password

+
+
+
I
+
+ QueryParameters + +
No documentation available
+
+
c
+
+ Queue + +
No documentation available
+
+
f
+
+ raise + +

Utility function that throws an error. +Band-aid for JS not supporting throwing in null-coalescing.

+
+
+
c
+
+ Random + +
No documentation available
+
+
c
+
+ RCON + +
No documentation available
+
+
c
+
+ Redis + +
No documentation available
+
+
c
+
+ Request + +
No documentation available
+
+
I
+
+ RequestParameters + +
No documentation available
+
+
c
+
+ Router + +
No documentation available
+
+
E
+
+ StatusCodes + +
No documentation available
+
+
c
+
+ Text + +
No documentation available
+
+
c
+
+ Time + +
No documentation available
+
+
f
+
+ TimeString + +

Takes a time string and turns it into milliseconds

+
+
+
f
+
+ TimeStringSeconds + +

Takes a time string and turns it into round seconds

+
+
+
I
+
+ ViewVariable + +
No documentation available
+
+
c
+
+ Webserver + +
No documentation available
+
+
c
+
+ Websocket + +
No documentation available
+
+
+
+
+
+ + diff --git a/docs/fuse.js b/docs/fuse.js new file mode 100644 index 00000000..a7eea4e3 --- /dev/null +++ b/docs/fuse.js @@ -0,0 +1,11 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file +/** + * Fuse.js v7.0.0 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2023 Kiro Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?$.getFn:n,o=t.fieldNormWeight,c=void 0===o?$.fieldNormWeight:o;r(this,e),this.norm=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(F).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),c=parseFloat(Math.round(o*r)/r);return n.set(i,c),c},clear:function(){n.clear()}}}(c,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,m(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();m(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?$.getFn:r,o=n.fieldNormWeight,c=void 0===o?$.fieldNormWeight:o,a=new R({getFn:i,fieldNormWeight:c});return a.setKeys(e.map(A)),a.setSources(t),a.create(),a}function N(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,c=t.expectedLocation,a=void 0===c?0:c,s=t.distance,u=void 0===s?$.distance:s,h=t.ignoreLocation,l=void 0===h?$.ignoreLocation:h,f=r/e.length;if(l)return f;var d=Math.abs(a-o);return u?f+d/u:d?1:f}var W=32;function T(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?$.location:i,c=r.distance,a=void 0===c?$.distance:c,s=r.threshold,u=void 0===s?$.threshold:s,h=r.findAllMatches,l=void 0===h?$.findAllMatches:h,f=r.minMatchCharLength,d=void 0===f?$.minMatchCharLength:f,v=r.includeMatches,g=void 0===v?$.includeMatches:v,y=r.ignoreLocation,p=void 0===y?$.ignoreLocation:y;if(t.length>W)throw new Error("Pattern length exceeds max of ".concat(W,"."));for(var m,k=t.length,M=e.length,b=Math.max(0,Math.min(o,M)),x=u,w=b,S=d>1||g,L=S?Array(M):[];(m=e.indexOf(t,w))>-1;){var _=N(t,{currentLocation:m,expectedLocation:b,distance:a,ignoreLocation:p});if(x=Math.min(_,x),w=m+k,S)for(var O=0;O=P;D-=1){var K=D-1,q=n[e.charAt(K)];if(S&&(L[K]=+!!q),z[D]=(z[D+1]<<1|1)&q,E&&(z[D]|=(j[D+1]|j[D])<<1|1|j[D+1]),z[D]&C&&(A=N(t,{errors:E,currentLocation:K,expectedLocation:b,distance:a,ignoreLocation:p}))<=x){if(x=A,(w=K)<=b)break;P=Math.max(1,2*b-w)}}if(N(t,{errors:E+1,currentLocation:b,expectedLocation:b,distance:a,ignoreLocation:p})>x)break;j=z}var B={isMatch:w>=0,score:Math.max(.001,A)};if(S){var J=function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:$.minMatchCharLength,n=[],r=-1,i=-1,o=0,c=e.length;o=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}(L,d);J.length?g&&(B.indices=J):B.isMatch=!1}return B}function z(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,c=void 0===o?$.location:o,a=i.threshold,s=void 0===a?$.threshold:a,u=i.distance,h=void 0===u?$.distance:u,l=i.includeMatches,f=void 0===l?$.includeMatches:l,d=i.findAllMatches,v=void 0===d?$.findAllMatches:d,g=i.minMatchCharLength,y=void 0===g?$.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?$.isCaseSensitive:p,k=i.ignoreLocation,M=void 0===k?$.ignoreLocation:k;if(r(this,e),this.options={location:c,threshold:s,distance:h,includeMatches:f,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:M},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var b=function(e,t){n.chunks.push({pattern:e,alphabet:z(e),startIndex:t})},x=this.pattern.length;if(x>W){for(var w=0,S=x%W,L=x-S;w1&&void 0!==arguments[1]?arguments[1]:{},c=o.location,a=void 0===c?$.location:c,s=o.threshold,u=void 0===s?$.threshold:s,h=o.distance,l=void 0===h?$.distance:h,f=o.includeMatches,d=void 0===f?$.includeMatches:f,v=o.findAllMatches,g=void 0===v?$.findAllMatches:v,y=o.minMatchCharLength,p=void 0===y?$.minMatchCharLength:y,m=o.isCaseSensitive,k=void 0===m?$.isCaseSensitive:m,M=o.ignoreLocation,b=void 0===M?$.ignoreLocation:M;return r(this,n),(i=t.call(this,e))._bitapSearch=new D(e,{location:a,threshold:u,distance:l,includeMatches:d,findAllMatches:g,minMatchCharLength:p,isCaseSensitive:k,ignoreLocation:b}),i}return o(n,[{key:"search",value:function(e){return this._bitapSearch.searchIn(e)}}],[{key:"type",get:function(){return"fuzzy"}},{key:"multiRegex",get:function(){return/^"(.*)"$/}},{key:"singleRegex",get:function(){return/^(.*)$/}}]),n}(K),X=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){for(var t,n=0,r=[],i=this.pattern.length;(t=e.indexOf(this.pattern,n))>-1;)n=t+i,r.push([t,n-1]);var o=!!r.length;return{isMatch:o,score:o?0:1,indices:r}}}],[{key:"type",get:function(){return"include"}},{key:"multiRegex",get:function(){return/^'"(.*)"$/}},{key:"singleRegex",get:function(){return/^'(.*)$/}}]),n}(K),Y=[B,X,U,V,H,G,J,Q],Z=Y.length,ee=/ +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,te=new Set([Q.type,X.type]),ne=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=n.isCaseSensitive,o=void 0===i?$.isCaseSensitive:i,c=n.includeMatches,a=void 0===c?$.includeMatches:c,s=n.minMatchCharLength,u=void 0===s?$.minMatchCharLength:s,h=n.ignoreLocation,l=void 0===h?$.ignoreLocation:h,f=n.findAllMatches,d=void 0===f?$.findAllMatches:f,v=n.location,g=void 0===v?$.location:v,y=n.threshold,p=void 0===y?$.threshold:y,m=n.distance,k=void 0===m?$.distance:m;r(this,e),this.query=null,this.options={isCaseSensitive:o,includeMatches:a,minMatchCharLength:u,findAllMatches:d,ignoreLocation:l,location:g,threshold:p,distance:k},this.pattern=o?t:t.toLowerCase(),this.query=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.split("|").map((function(e){for(var n=e.trim().split(ee).filter((function(e){return e&&!!e.trim()})),r=[],i=0,o=n.length;i2&&void 0!==arguments[2]?arguments[2]:{}).auto,r=void 0===n||n;return ue(e)||(e=he(e)),function e(n){var i=Object.keys(n),o=function(e){return!!e[ae]}(n);if(!o&&i.length>1&&!ue(n))return e(he(n));if(function(e){return!g(e)&&b(e)&&!ue(e)}(n)){var c=o?n[ae]:i[0],a=o?n[se]:n[c];if(!m(a))throw new Error(function(e){return"Invalid value for key ".concat(e)}(c));var s={keyId:C(c),pattern:a};return r&&(s.searcher=ie(a,t)),s}var u={children:[],operator:i[0]};return i.forEach((function(t){var r=n[t];g(r)&&r.forEach((function(t){u.children.push(e(t))}))})),u}(e)}function fe(e,t){var n=e.matches;t.matches=[],x(n)&&n.forEach((function(e){if(x(e.indices)&&e.indices.length){var n={indices:e.indices,value:e.value};e.key&&(n.key=e.key.src),e.idx>-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function de(e,t){t.score=e.score}var ve=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;r(this,e),this.options=t(t({},$),i),this.options.useExtendedSearch,this._keyStore=new j(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof R))throw new Error("Incorrect 'index' type");this._myIndex=t||P(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){x(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{}).limit,n=void 0===t?-1:t,r=this.options,i=r.includeMatches,o=r.includeScore,c=r.shouldSort,a=r.sortFn,s=r.ignoreFieldNorm,u=m(e)?m(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return function(e,t){var n=t.ignoreFieldNorm,r=void 0===n?$.ignoreFieldNorm:n;e.forEach((function(e){var t=1;e.matches.forEach((function(e){var n=e.key,i=e.norm,o=e.score,c=n?n.weight:null;t*=Math.pow(0===o&&c?Number.EPSILON:o,(c||1)*(r?1:i))})),e.score=t}))}(u,{ignoreFieldNorm:s}),c&&u.sort(a),k(n)&&n>-1&&(u=u.slice(0,n)),function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?$.includeMatches:r,o=n.includeScore,c=void 0===o?$.includeScore:o,a=[];return i&&a.push(fe),c&&a.push(de),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return a.length&&a.forEach((function(t){t(e,r)})),r}))}(u,this._docs,{includeMatches:i,includeScore:o})}},{key:"_searchStringList",value:function(e){var t=ie(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(x(n)){var c=t.searchIn(n),a=c.isMatch,s=c.score,u=c.indices;a&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:u}]})}})),r}},{key:"_searchLogical",value:function(e){var t=this,n=le(e,this.options),r=function e(n,r,i){if(!n.children){var o=n.keyId,c=n.searcher,a=t._findMatches({key:t._keyStore.get(o),value:t._myIndex.getValueForItemAtKeyId(r,o),searcher:c});return a&&a.length?[{idx:i,item:r,matches:a}]:[]}for(var s=[],u=0,h=n.children.length;u1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?$.getFn:n,i=t.fieldNormWeight,o=void 0===i?$.fieldNormWeight:i,c=e.keys,a=e.records,s=new R({getFn:r,fieldNormWeight:o});return s.setKeys(c),s.setIndexRecords(a),s},ve.config=$,function(){re.push.apply(re,arguments)}(ne),ve},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..4ddb3776 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,65 @@ + + + + Index - Chomp documentation + + + + + + + + + + + + + + + + diff --git a/docs/page.css b/docs/page.css new file mode 100644 index 00000000..1e054bd1 --- /dev/null +++ b/docs/page.css @@ -0,0 +1 @@ +*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{color:inherit;border-top-width:1px;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.mb-6{margin-bottom:1.5rem}.block{display:block}.flex{display:flex}.flex-1{flex:1}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-4{gap:1rem}.overflow-hidden{overflow:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.bg-transparent{background-color:#0000}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.italic{font-style:italic}.leading-none{line-height:1}.text-stone-400{--tw-text-opacity:1;color:rgb(168 162 158/var(--tw-text-opacity))}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}body{width:100%;max-width:1280px;margin-left:auto;margin-right:auto;padding:1.75rem;overflow-x:hidden}#content{gap:1.5rem;display:flex;position:relative}#content>main{flex:1}.toc{box-sizing:border-box;flex:none;width:16rem;max-height:100vh;position:sticky;top:0}@media not all and (min-width:1024px){.toc{display:none}}.toc>div{max-height:100%;overflow-y:scroll}.toc>div>:last-child{padding-bottom:1rem}#searchResults{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));display:none;position:absolute;inset:0}.hover\:bg-stone-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 244/var(--tw-bg-opacity))}@media not all and (min-width:1024px){.max-lg\:flex-col-reverse{flex-direction:column-reverse}}@media (min-width:1024px){.lg\:max-w-80{max-width:20rem}.lg\:items-center{align-items:center}} \ No newline at end of file diff --git a/docs/script.js b/docs/script.js new file mode 100644 index 00000000..15032006 --- /dev/null +++ b/docs/script.js @@ -0,0 +1,33 @@ +function findParent(el, find) { + do { + if (find(el)) { + return el; + } + } while (el = el.parentElement); +} + +document.addEventListener("click", (e) => { + const target = findParent( + e.target, + (el) => el instanceof HTMLButtonElement && el.dataset["copy"], + ); + if (target) { + navigator?.clipboard?.writeText(target.dataset["copy"]); + } +}); + +window.addEventListener("load", () => { + const usageSelector = document.getElementById("usageSelector"); + + document.addEventListener("mouseup", (e) => { + if ( + findParent( + e.target, + (el) => + el.parentElement === usageSelector && el instanceof HTMLDivElement, + ) + ) { + usageSelector.open = false; + } + }); +}); diff --git a/docs/search.js b/docs/search.js new file mode 100644 index 00000000..c1495058 --- /dev/null +++ b/docs/search.js @@ -0,0 +1,168 @@ +const Fuse = window.Fuse; + +const searchInput = document.querySelector("#searchbar"); +const mainContentTags = document.getElementsByTagName("main"); +const searchResultsDiv = document.querySelector("#searchResults"); +const currentFile = + document.querySelector("meta[name='doc-current-file']").attributes + .getNamedItem("content").value; +const pathToRoot = "../".repeat( + currentFile ? (currentFile.split("/").length + 1) : 0, +); +searchInput.removeAttribute("style"); + +const SEARCH_INDEX = window.DENO_DOC_SEARCH_INDEX; + +const fuse = new Fuse(SEARCH_INDEX.nodes, { + keys: [{ + name: "name", + weight: 2, + }], + isCaseSensitive: false, + minMatchCharLength: 2, + threshold: 0.4, +}); + +const loadedUrl = new URL(window.location.href); +const val = loadedUrl.searchParams.get("q"); +if (val) { + searchInput.value = val; + doSearch(val); +} + +window.addEventListener("load", function () { + document.addEventListener("keydown", function (event) { + if (event.key.toLowerCase() === "s") { + if (event.target !== searchInput) { + searchInput.focus(); + event.preventDefault(); + } + } + }); + + const emptyPlaceholder = "Click or press 'S' to search..."; + searchInput.placeholder = emptyPlaceholder; + + searchInput.addEventListener("focus", function () { + searchInput.placeholder = "Type your query here..."; + }); + + searchInput.addEventListener("blur", function () { + searchInput.placeholder = emptyPlaceholder; + }); +}); + +function debounce(func, delay) { + let timerId; + + return function () { + const context = this; + const args = arguments; + + clearTimeout(timerId); + + timerId = setTimeout(function () { + func.apply(context, args); + }, delay); + }; +} + +const debouncedSearch = debounce(doSearch, 250); + +searchInput.addEventListener("input", (e) => { + const val = e.target.value; + debouncedSearch(val); +}); + +function doSearch(val) { + if (!val) { + updateCurrentLocation(val); + showPage(); + } else { + const results = searchInIndex(val); + // console.log("results", results); + updateCurrentLocation(val); + renderResults(results); + showSearchResults(); + } +} + +function updateCurrentLocation(val) { + const url = new URL(window.location.href); + if (val) { + url.searchParams.set("q", val); + } else { + url.searchParams.delete("q"); + } + window.history.replaceState({}, "", url.href); +} + +function showPage() { + for (const mainTag of mainContentTags) { + mainTag.style.display = "block"; + } + searchResultsDiv.style.display = "none"; +} + +function showSearchResults() { + for (const mainTag of mainContentTags) { + mainTag.style.display = "none"; + } + searchResultsDiv.style.display = "block"; +} + +function renderResults(results) { + if (results.length === 0) { + searchResultsDiv.innerHTML = `No result`; + return; + } + + let html = ``; + searchResultsDiv.innerHTML = html; +} + +function searchInIndex(val) { + return fuse.search(val).map((result) => result.item); +} + +function docNodeKindToStringVariants(kind) { + switch (kind) { + case "function": + return ["Function", "Function", "f"]; + case "variable": + return ["Variable", "Variable", "v"]; + case "class": + return ["Class", "Class", "c"]; + case "enum": + return ["Enum", "Enum", "E"]; + case "interface": + return ["Interface", "Interface", "I"]; + case "typeAlias": + return ["TypeAlias", "Type Alias", "T"]; + case "namespace": + return ["Namespace", "Namespace", "N"]; + default: + return []; + } +} diff --git a/docs/search_index.js b/docs/search_index.js new file mode 100644 index 00000000..fe6ce6ac --- /dev/null +++ b/docs/search_index.js @@ -0,0 +1,3 @@ +(function () { + window.DENO_DOC_SEARCH_INDEX = {"nodes":[{"kind":["enum"],"name":"Algorithms","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":229},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Authenticator","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":95},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Cache","file":".","location":{"filename":"","line":10,"col":0,"byteIndex":222},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"CheckSource","file":".","location":{"filename":"","line":38,"col":0,"byteIndex":1093},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Configure","file":".","location":{"filename":"","line":9,"col":0,"byteIndex":233},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Controller","file":".","location":{"filename":"","line":15,"col":0,"byteIndex":574},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"CouchDB","file":".","location":{"filename":"","line":21,"col":0,"byteIndex":355},"declarationKind":"export","deprecated":false},{"kind":["function","namespace"],"name":"Cron","file":".","location":{"filename":"","line":56,"col":0,"byteIndex":2427},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"Cron.Cron","file":".","location":{"filename":"","line":325,"col":5,"byteIndex":9058},"declarationKind":"declare","deprecated":false},{"kind":["variable"],"name":"DEFAULT_OPTS","file":".","location":{"filename":"","line":52,"col":13,"byteIndex":1435},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Druid","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["enum"],"name":"ErrorCodes","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Events","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":102},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"ExclusionConfig","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":94},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"File","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Folder","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":47},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"GraphQL","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Hash","file":".","location":{"filename":"","line":50,"col":0,"byteIndex":1339},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"INSECURE_ALGORITHMS","file":".","location":{"filename":"","line":41,"col":13,"byteIndex":1177},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Inflector","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":63},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"InfluxDB","file":".","location":{"filename":"","line":16,"col":0,"byteIndex":184},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Logger","file":".","location":{"filename":"","line":44,"col":0,"byteIndex":1500},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Loki","file":".","location":{"filename":"","line":9,"col":0,"byteIndex":179},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Ntfy","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":48},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Nut","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":152},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"PASSWORD_DEFAULT","file":".","location":{"filename":"","line":8,"col":13,"byteIndex":247},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Password","file":".","location":{"filename":"","line":67,"col":0,"byteIndex":1718},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"PasswordOptions","file":".","location":{"filename":"","line":60,"col":0,"byteIndex":1549},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"QueryParameters","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":118},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Queue","file":".","location":{"filename":"","line":20,"col":0,"byteIndex":333},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"RCON","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":132},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Random","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Redis","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":148},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Request","file":".","location":{"filename":"","line":11,"col":0,"byteIndex":186},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"RequestParameters","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":48},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Router","file":".","location":{"filename":"","line":20,"col":0,"byteIndex":762},"declarationKind":"export","deprecated":false},{"kind":["enum"],"name":"StatusCodes","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Text","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Time","file":".","location":{"filename":"","line":5,"col":0,"byteIndex":242},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"TimeString","file":".","location":{"filename":"","line":77,"col":0,"byteIndex":1556},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"TimeStringSeconds","file":".","location":{"filename":"","line":97,"col":0,"byteIndex":2157},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"ViewVariable","file":".","location":{"filename":"","line":11,"col":0,"byteIndex":499},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Webserver","file":".","location":{"filename":"","line":5,"col":0,"byteIndex":145},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Websocket","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":289},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"raise","file":".","location":{"filename":"","line":38,"col":0,"byteIndex":927},"declarationKind":"export","deprecated":false}]}; +})() \ No newline at end of file diff --git a/docs/styles.css b/docs/styles.css new file mode 100644 index 00000000..ff3c7e07 --- /dev/null +++ b/docs/styles.css @@ -0,0 +1 @@ +.ddoc .container{width:100%}@media (min-width:640px){.ddoc .container{max-width:640px}}@media (min-width:768px){.ddoc .container{max-width:768px}}@media (min-width:1024px){.ddoc .container{max-width:1024px}}@media (min-width:1280px){.ddoc .container{max-width:1280px}}@media (min-width:1536px){.ddoc .container{max-width:1536px}}.ddoc .static{position:static}.ddoc .relative{position:relative}.ddoc .\!mb-0{margin-bottom:0!important}.ddoc .\!ml-2{margin-left:.5rem!important}.ddoc .ml-2{margin-left:.5rem}.ddoc .ml-4{margin-left:1rem}.ddoc .mr-2{margin-right:.5rem}.ddoc .mt-3{margin-top:.75rem}.ddoc .block{display:block}.ddoc .inline{display:inline}.ddoc .flex{display:flex}.ddoc .inline-flex{display:inline-flex}.ddoc .table{display:table}.ddoc .contents{display:contents}.ddoc .hidden{display:none}.ddoc .h-4{height:1rem}.ddoc .h-5{height:1.25rem}.ddoc .min-w-0{min-width:0}.ddoc .flex-1{flex:1}.ddoc .flex-none{flex:none}.ddoc .grow{flex-grow:1}.ddoc .rotate-90{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.ddoc .items-center{align-items:center}.ddoc .gap-0{gap:0}.ddoc .gap-0\.5{gap:.125rem}.ddoc .gap-1{gap:.25rem}.ddoc .gap-2{gap:.5rem}.ddoc .space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*calc(1 - var(--tw-space-x-reverse)))}.ddoc .space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*calc(1 - var(--tw-space-x-reverse)))}.ddoc .space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.ddoc .space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.ddoc .space-y-7>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.75rem*var(--tw-space-y-reverse))}.ddoc .overflow-x-auto{overflow-x:auto}.ddoc .break-words{overflow-wrap:break-word}.ddoc .break-all{word-break:break-all}.ddoc .rounded-full{border-radius:9999px}.ddoc .border{border-width:1px}.ddoc .border-l-2{border-left-width:2px}.ddoc .border-stone-300{--tw-border-opacity:1;border-color:rgb(214 211 209/var(--tw-border-opacity))}.ddoc .bg-Class\/15{background-color:#20b44b26}.ddoc .bg-Enum\/15{background-color:#22abb026}.ddoc .bg-Function\/15{background-color:#056cf026}.ddoc .bg-Interface\/15{background-color:#d2a06426}.ddoc .bg-Method\/15{background-color:#056cf026}.ddoc .bg-Namespace\/15{background-color:#d2564626}.ddoc .bg-Property\/15{background-color:#7e57c026}.ddoc .bg-TypeAlias\/15{background-color:#a4478c26}.ddoc .bg-Variable\/15{background-color:#7e57c026}.ddoc .bg-abstract\/15{background-color:#0cafc626}.ddoc .bg-deprecated\/15{background-color:#dc262626}.ddoc .bg-new\/15{background-color:#7b61ff26}.ddoc .bg-optional\/15{background-color:#0cafc626}.ddoc .bg-other\/15{background-color:#57534e26}.ddoc .bg-permissions\/15{background-color:#0cafc626}.ddoc .bg-private\/15,.ddoc .bg-protected\/15,.ddoc .bg-readonly\/15,.ddoc .bg-writeonly\/15{background-color:#7b61ff26}.ddoc .px-2{padding-left:.5rem;padding-right:.5rem}.ddoc .px-3{padding-left:.75rem;padding-right:.75rem}.ddoc .py-1{padding-top:.25rem;padding-bottom:.25rem}.ddoc .py-2{padding-top:.5rem;padding-bottom:.5rem}.ddoc .pl-4{padding-left:1rem}.ddoc .text-sm{font-size:.875rem;line-height:1.25rem}.ddoc .text-xl{font-size:1.25rem;line-height:1.75rem}.ddoc .font-bold{font-weight:700}.ddoc .font-medium{font-weight:500}.ddoc .font-normal{font-weight:400}.ddoc .italic{font-style:italic}.ddoc .leading-none{line-height:1}.ddoc .text-Class{--tw-text-opacity:1;color:rgb(32 180 75/var(--tw-text-opacity))}.ddoc .text-Enum{--tw-text-opacity:1;color:rgb(34 171 176/var(--tw-text-opacity))}.ddoc .text-Function{--tw-text-opacity:1;color:rgb(5 108 240/var(--tw-text-opacity))}.ddoc .text-Interface{--tw-text-opacity:1;color:rgb(210 160 100/var(--tw-text-opacity))}.ddoc .text-Method{--tw-text-opacity:1;color:rgb(5 108 240/var(--tw-text-opacity))}.ddoc .text-Namespace{--tw-text-opacity:1;color:rgb(210 86 70/var(--tw-text-opacity))}.ddoc .text-Property{--tw-text-opacity:1;color:rgb(126 87 192/var(--tw-text-opacity))}.ddoc .text-TypeAlias{--tw-text-opacity:1;color:rgb(164 71 140/var(--tw-text-opacity))}.ddoc .text-Variable{--tw-text-opacity:1;color:rgb(126 87 192/var(--tw-text-opacity))}.ddoc .text-\[\#0F172A\]{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity))}.ddoc .text-abstract{--tw-text-opacity:1;color:rgb(12 175 198/var(--tw-text-opacity))}.ddoc .text-deprecated{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity))}.ddoc .text-new{--tw-text-opacity:1;color:rgb(123 97 255/var(--tw-text-opacity))}.ddoc .text-optional{--tw-text-opacity:1;color:rgb(12 175 198/var(--tw-text-opacity))}.ddoc .text-other{--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity))}.ddoc .text-permissions{--tw-text-opacity:1;color:rgb(12 175 198/var(--tw-text-opacity))}.ddoc .text-private,.ddoc .text-protected,.ddoc .text-readonly,.ddoc .text-writeonly{--tw-text-opacity:1;color:rgb(123 97 255/var(--tw-text-opacity))}.ddoc summary::-webkit-details-marker{display:none}.ddoc{--ddoc-selection-border-width:2px;--ddoc-selection-border-color-default:#d6d3d1;--ddoc-selection-selected-border-color:#2564eb;--ddoc-selection-selected-bg:#056cf00c;--ddoc-selection-padding:9px 15px}.ddoc .link{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:75ms;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ddoc .link:hover{--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity))}.ddoc .anchor{float:left;--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity));margin-left:-24px;padding:.25rem;line-height:1;display:none;top:0;bottom:0}.ddoc .anchorable{position:relative}.ddoc .anchorable:hover .anchor{display:block}.ddoc .deprecated>div:first-child{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity));align-items:center;gap:.25rem;padding-top:.25rem;padding-bottom:.25rem;display:flex}.ddoc .deprecated>div:first-child>span{font-weight:600;line-height:1.5rem}.ddoc .deprecated>div:nth-child(2){--tw-border-opacity:1;border-left-width:4px;border-color:rgb(252 165 165/var(--tw-border-opacity));margin-left:.25rem;padding-left:.5rem}.ddoc .symbolSubtitle>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.125rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem*var(--tw-space-y-reverse))}.ddoc .symbolSubtitle{font-size:.875rem;line-height:1rem}.ddoc .symbolSubtitle .type{--tw-text-opacity:1;color:rgb(168 162 158/var(--tw-text-opacity));font-style:italic}.ddoc .docEntry{font-size:.875rem;line-height:1.25rem}.ddoc .docEntry .docEntryHeader{justify-content:space-between;align-items:flex-start;display:flex}.ddoc .docEntry .docEntryHeader>span{overflow-wrap:break-word;align-items:center;gap:.5rem;display:flex}.ddoc .section>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.ddoc .section>div>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.ddoc .section>div>h2{padding-top:.25rem;padding-bottom:.25rem;font-size:1.25rem;font-weight:600;line-height:1.5rem}.ddoc .namespaceSection{grid-template-columns:repeat(1,minmax(0,1fr));row-gap:.75rem;display:grid}@media (min-width:768px){.ddoc .namespaceSection{-moz-column-gap:2rem;grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem}}@media (min-width:1024px){.ddoc .namespaceSection{grid-template-columns:repeat(3,minmax(0,1fr))}}.ddoc .namespaceSection .namespaceItem{-moz-column-gap:.625rem;column-gap:.625rem;display:flex}.ddoc .namespaceSection .namespaceItem .docNodeKindIcon{flex-direction:column;justify-content:flex-start;width:auto}.ddoc .namespaceSection .namespaceItem .docNodeKindIcon>*+*{margin-top:-.125rem;margin-left:0}.ddoc .namespaceSection .namespaceItem[aria-label=deprecated]{opacity:.6}.ddoc .namespaceSection .namespaceItem[aria-label=deprecated] .namespaceItemContent>a{--tw-text-opacity:1;color:rgb(120 113 108/var(--tw-text-opacity));text-decoration-line:line-through;text-decoration-color:#78716cb3;text-decoration-thickness:2px}.ddoc .namespaceSection .namespaceItem .namespaceItemContent>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.ddoc .namespaceSection .namespaceItem .namespaceItemContent>a{word-break:break-all;font-weight:500;line-height:1.25;display:block}.ddoc .namespaceSection .namespaceItem .namespaceItemContent>div{--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity));font-size:.875rem;line-height:1.25rem}.ddoc .symbolGroup>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(3rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(3rem*var(--tw-space-y-reverse))}.ddoc .symbolGroup article>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem*var(--tw-space-y-reverse))}.ddoc .symbolGroup article>div:first-child{justify-content:space-between;align-items:flex-start;display:flex}.ddoc .symbolGroup article>div:first-child>div:first-child>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.ddoc .symbolGroup article>div:first-child>div:first-child{font-weight:500}.ddoc .docNodeKindIcon{flex-shrink:0;justify-content:flex-end;display:inline-flex}.ddoc .docNodeKindIcon div{-webkit-user-select:none;user-select:none;text-align:center;vertical-align:middle;border-radius:9999px;flex-shrink:0;width:1.25rem;height:1.25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.75rem;font-weight:500;line-height:1.25rem}.ddoc .docNodeKindIcon>*+*{margin-left:-.375rem}.ddoc .example details summary{cursor:pointer;border-radius:.5rem;align-items:center;gap:.5rem;width:100%;padding-top:.5rem;padding-bottom:.5rem;line-height:1.5rem;list-style-type:none;display:flex}.ddoc .example details summary>div:first-child{-webkit-user-select:none;user-select:none;--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity))}.ddoc .example details[open] summary>div:first-child{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.ddoc .toc h3{margin-bottom:.75rem;font-size:1.125rem;font-weight:700;line-height:1.75rem}.ddoc .toc>div>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem*var(--tw-space-y-reverse))}.ddoc .toc .topSymbols>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.ddoc .toc .topSymbols{font-size:.875rem;line-height:1.25rem}.ddoc .toc .topSymbols ul{list-style-type:none}.ddoc .toc .topSymbols ul>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.625rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem*var(--tw-space-y-reverse))}.ddoc .toc .topSymbols ul li{display:block}.ddoc .toc .topSymbols ul li a{align-items:center;gap:.5rem;display:flex}.ddoc .toc .topSymbols ul li a>span{text-overflow:ellipsis;white-space:nowrap;border-radius:.25rem;width:100%;margin-top:-.125rem;margin-bottom:-.125rem;margin-left:-.25rem;padding-top:.125rem;padding-bottom:.125rem;padding-left:.25rem;display:block;overflow:hidden}.ddoc .toc .topSymbols>a:hover{text-decoration-line:underline}.ddoc .toc .documentNavigation>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.ddoc .toc .documentNavigation{font-size:.875rem;line-height:1.25rem}.ddoc .toc .documentNavigation>ul{display:block}.ddoc .toc .documentNavigation>ul>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.ddoc .toc .documentNavigation>ul{overflow-y:auto}.ddoc .toc .documentNavigation>ul ul{margin-left:.875rem}.ddoc .toc .documentNavigation>ul ul>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.ddoc .toc .documentNavigation a{text-overflow:ellipsis;white-space:nowrap;display:block;overflow-x:hidden}.ddoc .toc .documentNavigation a:hover{text-decoration-line:underline}.ddoc .usages nav{flex-direction:row;align-items:center;gap:.5rem;margin-bottom:.75rem;font-weight:600;display:flex}.ddoc .usages nav details>summary{cursor:pointer;-webkit-user-select:none;user-select:none;--tw-border-opacity:1;border-width:1px;border-color:rgb(209 213 219/var(--tw-border-opacity));border-radius:.25rem;gap:.25rem;padding:.5rem .75rem;display:flex}@media (min-width:768px){.ddoc .usages nav details>div{position:relative}}.ddoc .usages nav details>div>div{z-index:30;--tw-border-opacity:1;border-width:1px;border-color:rgb(209 213 219/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));margin-top:.375rem;padding:.5rem;display:block;position:absolute}@media not all and (min-width:768px){.ddoc .usages nav details>div>div{border-left-width:0;border-right-width:0;left:0;right:0}}@media (min-width:768px){.ddoc .usages nav details>div>div{border-radius:.25rem;width:12rem}}.ddoc .usages nav details>div>div label{cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:.125rem;align-items:center;gap:.5rem;padding:.25rem .5rem;line-height:1.5;display:flex}.ddoc .usages nav details>div>div label:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.ddoc .usageContent .markdown{--tw-text-opacity:1;color:rgb(104 104 104/var(--tw-text-opacity));font-size:.75rem;line-height:1rem}.ddoc .usageContent .markdown p{margin:0}.ddoc .usageContent pre.highlight{--tw-border-opacity:1;border-width:1px;border-color:rgb(209 213 219/var(--tw-border-opacity));background-color:#0000}@media not all and (min-width:768px){.ddoc .usageContent pre.highlight{border-left-width:0;border-right-width:0}}.ddoc .usageContent pre.highlight{margin-top:.25rem!important}.ddoc .usageContent pre.highlight>code:first-child{scrollbar-width:thin;padding:.5rem .75rem}.ddoc .usageContent pre.highlight .context_button{border-width:0;display:none;top:.25rem;right:.5rem}.ddoc .usageContent pre.highlight .context_button svg rect{fill:#fff}.ddoc .usageContent pre.highlight:hover .context_button{opacity:1;display:block}.ddoc .contextLink{color:#0e6590cc;text-underline-offset:4px;text-decoration-line:underline;text-decoration-color:#0e659080;text-decoration-thickness:1.5px}.ddoc .contextLink:hover{--tw-text-opacity:1;color:rgb(14 101 144/var(--tw-text-opacity));text-decoration-color:#0e6590}.ddoc .breadcrumbs{word-break:break-all;align-items:center;gap:.25rem;display:inline-flex}.ddoc .breadcrumbs>li:first-child{font-size:1.25rem;font-weight:700;line-height:1}@media (min-width:1024px){.ddoc .breadcrumbs>li:first-child{font-size:1.5rem;line-height:2rem}}.ddoc .breadcrumbs li{line-height:.9em;display:inline}@media (min-width:1024px){.ddoc .breadcrumbs li{font-size:1.25rem;line-height:1.75rem}}.ddoc .functionOverload{cursor:pointer;display:block}.ddoc .functionOverload>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.ddoc .functionOverload{--tw-border-opacity:1;border-width:1px;border-color:rgb(214 211 209/var(--tw-border-opacity));border-radius:.5rem;padding:.625rem 1rem}.ddoc .functionOverload:hover{--tw-bg-opacity:1;background-color:rgb(245 245 244/var(--tw-bg-opacity))}.ddoc .context_button{z-index:10;cursor:pointer;background-color:inherit;border-width:1px;border-radius:.25rem;padding:.375rem;line-height:0}.ddoc .context_button:hover{--tw-bg-opacity:1;background-color:rgb(231 229 228/var(--tw-bg-opacity))}.ddoc .markdown_border{border-color:#d6d3d166;border-left-width:2px;margin-left:.25rem;padding-left:.625rem}.ddoc .markdown_summary{--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity));display:inline}.ddoc .markdown_summary p{display:inline-block}.ddoc .markdown_summary :not(pre)>code{--tw-bg-opacity:1;background-color:rgb(231 229 228/var(--tw-bg-opacity));border-radius:.25rem;padding:.125rem .25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem}.ddoc .markdown{flex-shrink:1;min-width:0}.ddoc .markdown>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.ddoc .markdown a:not(.no_color){--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:75ms;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ddoc .markdown a:not(.no_color):hover{--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity))}.ddoc .markdown h1{--tw-border-opacity:1;border-bottom-width:1px;border-color:rgb(214 211 209/var(--tw-border-opacity));padding-bottom:.25rem;font-size:1.25rem;line-height:1.75rem}@media (min-width:768px){.ddoc .markdown h1{font-size:1.5rem;line-height:2rem}}@media (min-width:1024px){.ddoc .markdown h1{font-size:1.875rem;line-height:2.25rem}}.ddoc .markdown h2{--tw-border-opacity:1;border-bottom-width:1px;border-color:rgb(214 211 209/var(--tw-border-opacity));padding-bottom:.25rem;font-size:1.125rem;line-height:1.75rem}@media (min-width:768px){.ddoc .markdown h2{font-size:1.25rem;line-height:1.75rem}}@media (min-width:1024px){.ddoc .markdown h2{font-size:1.5rem;line-height:2rem}}.ddoc .markdown h3{font-weight:700}@media (min-width:768px){.ddoc .markdown h3{font-size:1.125rem;font-weight:400;line-height:1.75rem}}@media (min-width:1024px){.ddoc .markdown h3{font-size:1.25rem;font-weight:400;line-height:1.75rem}}.ddoc .markdown h4{font-weight:600}@media (min-width:768px){.ddoc .markdown h4{font-weight:700}}@media (min-width:1024px){.ddoc .markdown h4{font-size:1.125rem;font-weight:400;line-height:1.75rem}}.ddoc .markdown h5{font-style:italic}@media (min-width:768px){.ddoc .markdown h5{font-weight:600}}@media (min-width:1024px){.ddoc .markdown h5{font-weight:700}}@media (min-width:768px){.ddoc .markdown h6{font-style:italic}}@media (min-width:1024px){.ddoc .markdown h6{font-weight:600}}.ddoc .markdown hr{--tw-border-opacity:1;border-color:rgb(120 113 108/var(--tw-border-opacity));margin:.5rem}.ddoc .markdown ol,.ddoc .markdown ul{margin-left:1rem;list-style-position:outside}.ddoc .markdown ol{list-style-type:decimal}.ddoc .markdown ul{list-style-type:disc}.ddoc .markdown :not(pre)>code{--tw-bg-opacity:1;background-color:rgb(231 229 228/var(--tw-bg-opacity));border-radius:.25rem;padding:.125rem .25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem}:is(.ddoc .markdown h1,.ddoc .markdown h2,.ddoc .markdown h3,.ddoc .markdown h4,.ddoc .markdown h5,.ddoc .markdown h6)>code{font-size:inherit!important}.ddoc .markdown pre{--tw-bg-opacity:1;background-color:rgb(245 245 244/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity));border-radius:.5rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem}.ddoc .markdown pre>code:first-child{padding:1rem;display:block;overflow-x:auto}.ddoc .markdown p{margin:.25rem 0}.ddoc .markdown table{table-layout:auto;width:max-content;max-width:100%;display:block;overflow:auto}.ddoc .markdown td{--tw-border-opacity:1;border-width:1px;border-color:rgb(120 113 108/var(--tw-border-opacity));padding:.5rem}.ddoc .markdown th{text-align:center;font-weight:700}.ddoc .markdown img{display:inline-block}.ddoc .markdown .alert>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.ddoc .markdown .alert{border-left-width:4px;padding:.5rem 1rem}.ddoc .markdown .alert div:first-child{align-items:center;gap:.375rem;font-weight:500;display:flex}.ddoc .markdown .alert div:first-child svg{width:1.25rem;height:1.25rem}.ddoc .markdown .alert-note{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity))}.ddoc .markdown .alert-note div:first-child{stroke:#2563eb;--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.ddoc .markdown .alert-tip{--tw-border-opacity:1;border-color:rgb(22 163 74/var(--tw-border-opacity))}.ddoc .markdown .alert-tip div:first-child{stroke:#16a34a;--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity))}.ddoc .markdown .alert-important{--tw-border-opacity:1;border-color:rgb(147 51 234/var(--tw-border-opacity))}.ddoc .markdown .alert-important div:first-child{stroke:#9333ea;--tw-text-opacity:1;color:rgb(147 51 234/var(--tw-text-opacity))}.ddoc .markdown .alert-warning{--tw-border-opacity:1;border-color:rgb(202 138 4/var(--tw-border-opacity))}.ddoc .markdown .alert-warning div:first-child{stroke:#ca8a04;--tw-text-opacity:1;color:rgb(202 138 4/var(--tw-text-opacity))}.ddoc .markdown .alert-caution{--tw-border-opacity:1;border-color:rgb(220 38 38/var(--tw-border-opacity))}.ddoc .markdown .alert-caution div:first-child{stroke:#dc2626;--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity))}.ddoc .markdown .highlight{position:relative}.ddoc .markdown .highlight .lineNumbers{--tw-border-opacity:1;border-right-width:2px;border-color:rgb(214 211 209/var(--tw-border-opacity));text-align:right;flex:none;padding-right:.25rem}.ddoc .markdown .highlight .context_button{opacity:.6;position:absolute;top:.75rem;right:1rem}.ddoc .markdown .highlight .context_button:hover{opacity:1}.ddoc .markdown .highlight .pl-c{color:#6a737d}.ddoc .markdown .highlight .pl-c1,.ddoc .markdown .highlight .pl-s .pl-v{color:#005cc5}.ddoc .markdown .highlight .pl-e,.ddoc .markdown .highlight .pl-en{color:#6f42c1}.ddoc .markdown .highlight .pl-smi,.ddoc .markdown .highlight .pl-s .pl-s1{color:#24292e}.ddoc .markdown .highlight .pl-ent{color:#22863a}.ddoc .markdown .highlight .pl-k{color:#d73a49}.ddoc .markdown .highlight .pl-s,.ddoc .markdown .highlight .pl-pds,.ddoc .markdown .highlight .pl-s .pl-pse .pl-s1,.ddoc .markdown .highlight .pl-sr,.ddoc .markdown .highlight .pl-sr .pl-cce,.ddoc .markdown .highlight .pl-sr .pl-sre,.ddoc .markdown .highlight .pl-sr .pl-sra{color:#032f62}.ddoc .markdown .highlight .pl-v,.ddoc .markdown .highlight .pl-smw{color:#e36209}.ddoc .markdown .highlight .pl-bu{color:#b31d28}.ddoc .markdown .highlight .pl-ii{color:#fafbfc;background-color:#b31d28}.ddoc .markdown .highlight .pl-c2{color:#fafbfc;background-color:#d73a49}.ddoc .markdown .highlight .pl-c2:before{content:"^M"}.ddoc .markdown .highlight .pl-sr .pl-cce{color:#22863a;font-weight:700}.ddoc .markdown .highlight .pl-ml{color:#735c0f}.ddoc .markdown .highlight .pl-mh,.ddoc .markdown .highlight .pl-mh .pl-en,.ddoc .markdown .highlight .pl-ms{color:#005cc5;font-weight:700}.ddoc .markdown .highlight .pl-mi{color:#24292e;font-style:italic}.ddoc .markdown .highlight .pl-mb{color:#24292e;font-weight:700}.ddoc .markdown .highlight .pl-md{color:#b31d28;background-color:#ffeef0}.ddoc .markdown .highlight .pl-mi1{color:#22863a;background-color:#f0fff4}.ddoc .markdown .highlight .pl-mc{color:#e36209;background-color:#ffebda}.ddoc .markdown .highlight .pl-mi2{color:#f6f8fa;background-color:#005cc5}.ddoc .\*\:h-4>*{height:1rem}.ddoc .\*\:h-5>*{height:1.25rem}.ddoc .\*\:w-auto>*{width:auto}.ddoc .\*\:flex-none>*{flex:none}.ddoc .target\:bg-yellow-200:target{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.ddoc .hover\:bg-Class\/15:hover{background-color:#20b44b26}.ddoc .hover\:bg-Enum\/15:hover{background-color:#22abb026}.ddoc .hover\:bg-Function\/15:hover{background-color:#056cf026}.ddoc .hover\:bg-Interface\/15:hover{background-color:#d2a06426}.ddoc .hover\:bg-Method\/15:hover{background-color:#056cf026}.ddoc .hover\:bg-Namespace\/15:hover{background-color:#d2564626}.ddoc .hover\:bg-Property\/15:hover{background-color:#7e57c026}.ddoc .hover\:bg-TypeAlias\/15:hover{background-color:#a4478c26}.ddoc .hover\:bg-Variable\/15:hover{background-color:#7e57c026}.ddoc .hover\:bg-abstract\/15:hover{background-color:#0cafc626}.ddoc .hover\:bg-deprecated\/15:hover{background-color:#dc262626}.ddoc .hover\:bg-new\/15:hover{background-color:#7b61ff26}.ddoc .hover\:bg-optional\/15:hover{background-color:#0cafc626}.ddoc .hover\:bg-other\/15:hover{background-color:#57534e26}.ddoc .hover\:bg-permissions\/15:hover{background-color:#0cafc626}.ddoc .hover\:bg-private\/15:hover,.ddoc .hover\:bg-protected\/15:hover,.ddoc .hover\:bg-readonly\/15:hover,.ddoc .hover\:bg-writeonly\/15:hover{background-color:#7b61ff26} \ No newline at end of file diff --git a/docs/~/Algorithms.html b/docs/~/Algorithms.html new file mode 100644 index 00000000..beefce58 --- /dev/null +++ b/docs/~/Algorithms.html @@ -0,0 +1,1228 @@ + + + + Algorithms - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ enum Algorithms +
+ + + + +

List of algorithms supported by this library

+
+
+ + + + + + + + + + +
+ BLAKE2B = "BLAKE2B" + + + + + + +
+
+ + + + + + + + + + +
+ BLAKE2B256 = "BLAKE2B-256" + + + + + + +
+
+ + + + + + + + + + +
+ BLAKE2B384 = "BLAKE2B-384" + + + + + + +
+
+ + + + + + + + + + +
+ BLAKE2S = "BLAKE2S" + + + + + + +
+
+ + + + + + + + + + +
+ BLAKE3 = "BLAKE3" + + + + + + +
+
+ + + + + + + + + + +
+ KECCAK224 = "KECCAK-224" + + + + + + +
+
+ + + + + + + + + + +
+ KECCAK256 = "KECCAK-256" + + + + + + +
+
+ + + + + + + + + + +
+ KECCAK384 = "KECCAK-384" + + + + + + +
+
+ + + + + + + + + + +
+ KECCAK512 = "KECCAK-512" + + + + + + +
+
+ + + + + + + + + + +
+ MD5 = "MD5" + + + + + + +
+
+ + + + + + + + + + +
+ RIPEMD160 = "RIPEMD-160" + + + + + + +
+
+ + + + + + + + + + +
+ SHA1 = "SHA-1" + + + + + + +
+
+ + + + + + + + + + +
+ SHA224 = "SHA-224" + + + + + + +
+
+ + + + + + + + + + +
+ SHA256 = "SHA-256" + + + + + + +
+
+ + + + + + + + + + +
+ SHA384 = "SHA-384" + + + + + + +
+
+ + + + + + + + + + +
+ SHA3_224 = "SHA3-224" + + + + + + +
+
+ + + + + + + + + + +
+ SHA3_256 = "SHA3-256" + + + + + + +
+
+ + + + + + + + + + +
+ SHA3_384 = "SHA3-384" + + + + + + +
+
+ + + + + + + + + + +
+ SHA3_512 = "SHA3-512" + + + + + + +
+
+ + + + + + + + + + +
+ SHA512 = "SHA-512" + + + + + + +
+
+ + + + + + + + + + +
+ SHAKE128 = "SHAKE128" + + + + + + +
+
+ + + + + + + + + + +
+ SHAKE256 = "SHAKE256" + + + + + + +
+
+
+
+
+
+
+

Usage

import { Algorithms } from ".";
+
+
+
+
+ + diff --git a/docs/~/Authenticator.client.html b/docs/~/Authenticator.client.html new file mode 100644 index 00000000..e0f117f8 --- /dev/null +++ b/docs/~/Authenticator.client.html @@ -0,0 +1,253 @@ + + + + Authenticator.client - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Authenticator.client +
+ + + + +
+
+ +

Check whether the passed token matches the "websocket_client_auth" key in the Configure

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+
optional
+
token: string = + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Authenticator } from ".";
+
+
+
+
+ + diff --git a/docs/~/Authenticator.html b/docs/~/Authenticator.html new file mode 100644 index 00000000..4b214a60 --- /dev/null +++ b/docs/~/Authenticator.html @@ -0,0 +1,157 @@ + + + + Authenticator - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Authenticator } from ".";
+
+
+
+
+ + diff --git a/docs/~/Authenticator.prototype.html b/docs/~/Authenticator.prototype.html new file mode 100644 index 00000000..a8d916b2 --- /dev/null +++ b/docs/~/Authenticator.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Cache._items.html b/docs/~/Cache._items.html new file mode 100644 index 00000000..02def437 --- /dev/null +++ b/docs/~/Cache._items.html @@ -0,0 +1,156 @@ + + + + Cache._items - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cache.consume.html b/docs/~/Cache.consume.html new file mode 100644 index 00000000..7a27a919 --- /dev/null +++ b/docs/~/Cache.consume.html @@ -0,0 +1,372 @@ + + + + Cache.consume - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Cache.consume +
+ + + + +
+
+ +

Consume an item from the cache. +Differs from "Cache.get()" in that it removes the item afterwards.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
+
+const item = Cache.consume('cache item name');
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
optimistic: boolean = false + +
+ + + + +

Whether to serve expired items from the cache

+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ unknown | null + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cache.dump.html b/docs/~/Cache.dump.html new file mode 100644 index 00000000..d858377b --- /dev/null +++ b/docs/~/Cache.dump.html @@ -0,0 +1,243 @@ + + + + Cache.dump - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Cache.dump +
+ + + + +
+
+ +

Dumps the raw cache contents. +Should only be used for debugging purposes.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
+
+console.log(Cache.dump());
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Map<string, CacheItem> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cache.exists.html b/docs/~/Cache.exists.html new file mode 100644 index 00000000..e774f555 --- /dev/null +++ b/docs/~/Cache.exists.html @@ -0,0 +1,319 @@ + + + + Cache.exists - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Cache.exists +
+ + + + +
+
+ +

Check whether an item exists in the cache. +This does not check whether the item has expired or not.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
+
+const doesExist = Cache.exists('cache item name');
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cache.expired.html b/docs/~/Cache.expired.html new file mode 100644 index 00000000..447c1c0a --- /dev/null +++ b/docs/~/Cache.expired.html @@ -0,0 +1,318 @@ + + + + Cache.expired - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Cache.expired +
+ + + + +
+
+ +

Check whether an item has expired

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
+
+const hasExpired = Cache.expired('cache item name');
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cache.get.html b/docs/~/Cache.get.html new file mode 100644 index 00000000..076797a5 --- /dev/null +++ b/docs/~/Cache.get.html @@ -0,0 +1,412 @@ + + + + Cache.get - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Cache.get +
+ + + + +
+
+ +

Get an item from the cache

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
+
+Cache.get('cache item name');
+
+
+
+
+
+ + + + + + + + + + +
+ +

Getting expired items

+
+
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
+
+const item = Cache.get('cache item name', true);
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
optimistic: boolean = false + +
+ + + + +

Whether to serve expired items from the cache

+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ unknown | null + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cache.html b/docs/~/Cache.html new file mode 100644 index 00000000..8dc96e44 --- /dev/null +++ b/docs/~/Cache.html @@ -0,0 +1,602 @@ + + + + Cache - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Cache +
+ + + + +
+
+

+ + + + + + + + + + +Static Properties

+ + + + + + + + + + +
+
private
+
_items: Map<string, CacheItem> + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Static Methods

+ + + + + + + + + + +
+ consume(key: string, optimistic?: boolean): unknown | null + + + + + + +

Consume an item from the cache. +Differs from "Cache.get()" in that it removes the item afterwards.

+
+
+ + + + + + + + + + +
+ dump(): Map<string, CacheItem> + + + + + + +

Dumps the raw cache contents. +Should only be used for debugging purposes.

+
+
+ + + + + + + + + + +
+ exists(key: string): boolean + + + + + + +

Check whether an item exists in the cache. +This does not check whether the item has expired or not.

+
+
+ + + + + + + + + + +
+ expired(key: string): boolean + + + + + + +

Check whether an item has expired

+
+
+ + + + + + + + + + +
+ get(key: string, optimistic?: boolean): unknown | null + + + + + + +

Get an item from the cache

+
+
+ + + + + + + + + + +
+ remove(key: string): void + + + + + + +

Remove an item from the cache

+
+
+ + + + + + + + + + +
+ set(key: string, value: unknown, expiry?: string | null): void + + + + + + +

Add an item to the cache.

+
+
+ + + + + + + + + + +
+ sweep(): void + + + + + + +

Scan the cache and clean up expired items while keeping optimistic caching in tact. +There shouldn't be a need to manually run this in most cases.

+
+
+
+
+
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cache.prototype.html b/docs/~/Cache.prototype.html new file mode 100644 index 00000000..09ce7189 --- /dev/null +++ b/docs/~/Cache.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Cache.remove.html b/docs/~/Cache.remove.html new file mode 100644 index 00000000..6abff0e6 --- /dev/null +++ b/docs/~/Cache.remove.html @@ -0,0 +1,318 @@ + + + + Cache.remove - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Cache.remove +
+ + + + +
+
+ +

Remove an item from the cache

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
+
+Cache.remove('cache item name');
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cache.set.html b/docs/~/Cache.set.html new file mode 100644 index 00000000..ccb9cb92 --- /dev/null +++ b/docs/~/Cache.set.html @@ -0,0 +1,427 @@ + + + + Cache.set - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Cache.set +
+ + + + +
+
+ +

Add an item to the cache.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
+
+Cache.set('I expire in 1 minute', 'foo');
+Cache.set('I expire in 10 minutes', 'bar', '+10 minutes');
+Cache.set('I never expire', 'baz', null);
+
+

NOTE: Expiry times use TimeString formats.

+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+ + + + + + + + + + +
+ value: unknown + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
expiry: string | null = +1 minute + +
+ + + + +

Can be set to null for never expiring items

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cache.sweep.html b/docs/~/Cache.sweep.html new file mode 100644 index 00000000..c8ab8c72 --- /dev/null +++ b/docs/~/Cache.sweep.html @@ -0,0 +1,243 @@ + + + + Cache.sweep - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Cache.sweep +
+ + + + +
+
+ +

Scan the cache and clean up expired items while keeping optimistic caching in tact. +There shouldn't be a need to manually run this in most cases.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
+
+Cache.sweep();
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Cache } from ".";
+
+
+
+
+ + diff --git a/docs/~/CheckSource.html b/docs/~/CheckSource.html new file mode 100644 index 00000000..2fad0287 --- /dev/null +++ b/docs/~/CheckSource.html @@ -0,0 +1,679 @@ + + + + CheckSource - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class CheckSource +
+ + + + +

Check all files in the specified directories. +Doing this allows the program to start up significantly faster after deployment. +It is NOT a replacement for "deno lint".

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { CheckSource } from "https://deno.land/x/chomp/utility/check-source.ts";
+
+const checker = new CheckSource(['./src']);
+await checker.run();
+
+
+
+
+
+ + + + + + + + + + +
+ +

Exclude a directory

+
+
import { CheckSource } from "https://deno.land/x/chomp/utility/check-source.ts";
+
+const checker = new CheckSource(['./src'], { directories: 'my-directory' });
+await checker.run();
+
+
+
+
+
+ + + + + + + + + + +
+ +

Exclude a file

+
+
import { CheckSource } from "https://deno.land/x/chomp/utility/check-source.ts";
+
+const checker = new CheckSource(['./src'], { files: './src/my-directory/my-file.txt' });
+await checker.run();
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
CheckSource(paths: string[], exclusions?: ExclusionConfig) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+ + + + + + + + + + +
+
private
+
errors: number + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
files: string[] + +
+ + + + +
+
+
+
+ + + + + + + + + + +
+
private
+
addFile(path: string): void + +
+ + + + +

Add file to array of files

+
+
+ + + + + + + + + + +
+
private
+
checkFiles(): Promise<void> + +
+ + + + +

Check all files found

+
+
+ + + + + + + + + + +
+
private
+
getFiles(path: string): Promise<void> + +
+ + + + +

Recursively can all files in the given path +Ignore directories and files given in our exclusions

+
+
+ + + + + + + + + + +
+ run(): Promise<void> + + + + + + +
+
+
+
+
+
+
+

Usage

import { CheckSource } from ".";
+
+
+
+
+ + diff --git a/docs/~/CheckSource.prototype.addFile.html b/docs/~/CheckSource.prototype.addFile.html new file mode 100644 index 00000000..5394cd38 --- /dev/null +++ b/docs/~/CheckSource.prototype.addFile.html @@ -0,0 +1,252 @@ + + + + CheckSource.prototype.addFile - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CheckSource.prototype.addFile +
+ + + + +
+
+ +

Add file to array of files

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ path: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { CheckSource } from ".";
+
+
+
+
+ + diff --git a/docs/~/CheckSource.prototype.checkFiles.html b/docs/~/CheckSource.prototype.checkFiles.html new file mode 100644 index 00000000..81408c2b --- /dev/null +++ b/docs/~/CheckSource.prototype.checkFiles.html @@ -0,0 +1,176 @@ + + + + CheckSource.prototype.checkFiles - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CheckSource.prototype.checkFiles +
+ + + + +
+
+ +

Check all files found

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CheckSource } from ".";
+
+
+
+
+ + diff --git a/docs/~/CheckSource.prototype.errors.html b/docs/~/CheckSource.prototype.errors.html new file mode 100644 index 00000000..be0a3742 --- /dev/null +++ b/docs/~/CheckSource.prototype.errors.html @@ -0,0 +1,156 @@ + + + + CheckSource.prototype.errors - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { CheckSource } from ".";
+
+
+
+
+ + diff --git a/docs/~/CheckSource.prototype.files.html b/docs/~/CheckSource.prototype.files.html new file mode 100644 index 00000000..3b6f3a33 --- /dev/null +++ b/docs/~/CheckSource.prototype.files.html @@ -0,0 +1,156 @@ + + + + CheckSource.prototype.files - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { CheckSource } from ".";
+
+
+
+
+ + diff --git a/docs/~/CheckSource.prototype.getFiles.html b/docs/~/CheckSource.prototype.getFiles.html new file mode 100644 index 00000000..f4f56cb0 --- /dev/null +++ b/docs/~/CheckSource.prototype.getFiles.html @@ -0,0 +1,253 @@ + + + + CheckSource.prototype.getFiles - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CheckSource.prototype.getFiles +
+ + + + +
+
+ +

Recursively can all files in the given path +Ignore directories and files given in our exclusions

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ path: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CheckSource } from ".";
+
+
+
+
+ + diff --git a/docs/~/CheckSource.prototype.html b/docs/~/CheckSource.prototype.html new file mode 100644 index 00000000..6249742a --- /dev/null +++ b/docs/~/CheckSource.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/CheckSource.prototype.run.html b/docs/~/CheckSource.prototype.run.html new file mode 100644 index 00000000..9bb08b50 --- /dev/null +++ b/docs/~/CheckSource.prototype.run.html @@ -0,0 +1,175 @@ + + + + CheckSource.prototype.run - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CheckSource.prototype.run +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CheckSource } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.check.html b/docs/~/Configure.check.html new file mode 100644 index 00000000..d46a345b --- /dev/null +++ b/docs/~/Configure.check.html @@ -0,0 +1,321 @@ + + + + Configure.check - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Configure.check +
+ + + + +
+
+ +

Return whether a key exists

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+const exists = Configure.check('my-item');
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ boolean + + + + + + +

boolean

+
+
+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.clear.html b/docs/~/Configure.clear.html new file mode 100644 index 00000000..b753bd7b --- /dev/null +++ b/docs/~/Configure.clear.html @@ -0,0 +1,246 @@ + + + + Configure.clear - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Configure.clear +
+ + + + +
+
+ +

Clear all items in the configure (including defaults). +If you want to keep the defaults, use Configure.reset() | Configure.reset() instead.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+Configure.clear();
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ void + + + + + + +

void

+
+
+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.config.html b/docs/~/Configure.config.html new file mode 100644 index 00000000..4378f13e --- /dev/null +++ b/docs/~/Configure.config.html @@ -0,0 +1,156 @@ + + + + Configure.config - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.consume.html b/docs/~/Configure.consume.html new file mode 100644 index 00000000..60db3fa3 --- /dev/null +++ b/docs/~/Configure.consume.html @@ -0,0 +1,415 @@ + + + + Configure.consume - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Configure.consume +
+ + + + +
+
+ +

Consume a key from configure (removing it).

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+const exists = Configure.consume('my-item');
+
+
+
+
+
+ + + + + + + + + + +
+ +

Setting a default value

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+const exists = Configure.consume('my-item', 'default-value');
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
defaultValue: any = null + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.delete.html b/docs/~/Configure.delete.html new file mode 100644 index 00000000..3738ae19 --- /dev/null +++ b/docs/~/Configure.delete.html @@ -0,0 +1,321 @@ + + + + Configure.delete - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Configure.delete +
+ + + + +
+
+ +

Delete a ConfigureItem from the Configure

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+Configure.delete('my-item');
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ void + + + + + + +

void

+
+
+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.dump.html b/docs/~/Configure.dump.html new file mode 100644 index 00000000..90a0dd8d --- /dev/null +++ b/docs/~/Configure.dump.html @@ -0,0 +1,245 @@ + + + + Configure.dump - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Configure.dump +
+ + + + +
+
+ +

Dump all contents of the Configure

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+console.log(Configure.dump());
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Map<string, any> + + + + + + +

ConfigureItem[]

+
+
+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.get.html b/docs/~/Configure.get.html new file mode 100644 index 00000000..30367aa1 --- /dev/null +++ b/docs/~/Configure.get.html @@ -0,0 +1,418 @@ + + + + Configure.get - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Configure.get +
+ + + + +
+
+ +

Obtain the value of a key in the configure.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+const item = Configure.get('my-item');
+
+
+
+
+
+ + + + + + + + + + +
+ +

Setting a default value

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+const item = Configure.get('my-item', 'my-default');
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +

Key to look for

+
+
+ + + + + + + + + + +
+
optional
+
defaultValue: any = null + +
+ + + + +

Default value to return when no result was found

+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ any | null + + + + + + +

any|null

+
+
+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.hasLoaded.html b/docs/~/Configure.hasLoaded.html new file mode 100644 index 00000000..f293614c --- /dev/null +++ b/docs/~/Configure.hasLoaded.html @@ -0,0 +1,156 @@ + + + + Configure.hasLoaded - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.html b/docs/~/Configure.html new file mode 100644 index 00000000..9069c210 --- /dev/null +++ b/docs/~/Configure.html @@ -0,0 +1,705 @@ + + + + Configure - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Configure +
+ + + + +
+
+

+ + + + + + + + + + +Static Properties

+ + + + + + + + + + +
+
private
+
config: Map<string, any> + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
hasLoaded: boolean + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Static Methods

+ + + + + + + + + + +
+ check(key: string): boolean + + + + + + +

Return whether a key exists

+
+
+ + + + + + + + + + +
+ clear(): void + + + + + + +

Clear all items in the configure (including defaults). +If you want to keep the defaults, use Configure.reset() | Configure.reset() instead.

+
+
+ + + + + + + + + + +
+ consume(key: string, defaultValue?: any): any + + + + + + +

Consume a key from configure (removing it).

+
+
+ + + + + + + + + + +
+ delete(key: string): void + + + + + + +

Delete a ConfigureItem from the Configure

+
+
+ + + + + + + + + + +
+ dump(): Map<string, any> + + + + + + +

Dump all contents of the Configure

+
+
+ + + + + + + + + + +
+ get(key: string, defaultValue?: any): any | null + + + + + + +

Obtain the value of a key in the configure.

+
+
+ + + + + + + + + + +
+ load(force?: boolean): Promise<void> + + + + + + +

Load our configure data from file

+
+
+ + + + + + + + + + +
+ reset(): void + + + + + + +

Resets the configure to the defaults. +If you do not want to keep the defaults, use "Configure.clear()" instead.

+
+
+ + + + + + + + + + +
+ set(key: string, value: any): void + + + + + + +

Set a configure item +It is not possible to store null values

+
+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.load.html b/docs/~/Configure.load.html new file mode 100644 index 00000000..70b1f43a --- /dev/null +++ b/docs/~/Configure.load.html @@ -0,0 +1,321 @@ + + + + Configure.load - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Configure.load +
+ + + + +
+
+ +

Load our configure data from file

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+
optional
+
force: boolean = false + +
+ + + + +

Set to true to force re-loading the configure

+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +

void

+
+
+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.prototype.html b/docs/~/Configure.prototype.html new file mode 100644 index 00000000..ccaf5c3a --- /dev/null +++ b/docs/~/Configure.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Configure.reset.html b/docs/~/Configure.reset.html new file mode 100644 index 00000000..49087331 --- /dev/null +++ b/docs/~/Configure.reset.html @@ -0,0 +1,245 @@ + + + + Configure.reset - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Configure.reset +
+ + + + +
+
+ +

Resets the configure to the defaults. +If you do not want to keep the defaults, use "Configure.clear()" instead.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+Configure.reset();
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Configure.set.html b/docs/~/Configure.set.html new file mode 100644 index 00000000..302a4329 --- /dev/null +++ b/docs/~/Configure.set.html @@ -0,0 +1,373 @@ + + + + Configure.set - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Configure.set +
+ + + + +
+
+ +

Set a configure item +It is not possible to store null values

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
+
+await Configure.load();
+Configure.set('my-item', 'my-value);
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+ + + + + + + + + + +
+ value: any + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ void + + + + + + +

void

+
+
+
+
+
+
+
+
+

Usage

import { Configure } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller._componentDir.html b/docs/~/Controller._componentDir.html new file mode 100644 index 00000000..85542aca --- /dev/null +++ b/docs/~/Controller._componentDir.html @@ -0,0 +1,156 @@ + + + + Controller._componentDir - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller._templateDir.html b/docs/~/Controller._templateDir.html new file mode 100644 index 00000000..2caa32f9 --- /dev/null +++ b/docs/~/Controller._templateDir.html @@ -0,0 +1,156 @@ + + + + Controller._templateDir - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.html b/docs/~/Controller.html new file mode 100644 index 00000000..6b76f065 --- /dev/null +++ b/docs/~/Controller.html @@ -0,0 +1,813 @@ + + + + Controller - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Controller +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
Controller(request: Request) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+ + + + + + + + + + +
+
writeonly
+
deprecated
+
type + +
+ + + + +

Set the 'Content-Type' header

+
+
+ + + + + + + + + + +
+
private
+
_response: ResponseBuilder + +
+ + + + +
+ +
+
+
+ + + + + + + + + + +
+
protected
+
getRequest(): Request + +
+ + + + +

Get the request object for this controller

+
+
+ + + + + + + + + + +
+
protected
+
getResponse(): ResponseBuilder + +
+ + + + +

Get the response object for this controller

+
+
+ + + + + + + + + + +
+ initialize(): Promise<void> + + + + + + +

Initialize the controller. +Literally does nothing at this moment except exist to prevent errors.

+
+
+ + + + + + + + + + +
+
protected
+
loadComponent(name: string): Promise<Controller> + +
+ + + + +
+
+ + + + + + + + + + +
+ render(): Promise<void> + + + + + + +

Render the page output +Will try to decide the best way of doing it based on the MIME set

+
+
+ + + + + + + + + + +
+
protected
+
set(key: string, value: string | number | unknown): void + +
+ + + + +

Set a view variable

+
+
+
+
+

+ + + + + + + + + + +Static Properties

+ + + + + + + + + + +
+
private
+
readonly
+
_componentDir: string + +
+ + + + +
+
+ + + + + + + + + + +
+
readonly
+
private
+
_templateDir: `./src/templates` + +
+ + + + +
+
+
+
+
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.prototype._response.html b/docs/~/Controller.prototype._response.html new file mode 100644 index 00000000..6d801215 --- /dev/null +++ b/docs/~/Controller.prototype._response.html @@ -0,0 +1,156 @@ + + + + Controller.prototype._response - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.prototype._vars.html b/docs/~/Controller.prototype._vars.html new file mode 100644 index 00000000..c90a659c --- /dev/null +++ b/docs/~/Controller.prototype._vars.html @@ -0,0 +1,156 @@ + + + + Controller.prototype._vars - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.prototype.getRequest.html b/docs/~/Controller.prototype.getRequest.html new file mode 100644 index 00000000..fe681c2c --- /dev/null +++ b/docs/~/Controller.prototype.getRequest.html @@ -0,0 +1,176 @@ + + + + Controller.prototype.getRequest - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Controller.prototype.getRequest +
+ + + + +
+
+ +

Get the request object for this controller

+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.prototype.getResponse.html b/docs/~/Controller.prototype.getResponse.html new file mode 100644 index 00000000..233efbf0 --- /dev/null +++ b/docs/~/Controller.prototype.getResponse.html @@ -0,0 +1,176 @@ + + + + Controller.prototype.getResponse - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Controller.prototype.getResponse +
+ + + + +
+
+ +

Get the response object for this controller

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ ResponseBuilder + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.prototype.html b/docs/~/Controller.prototype.html new file mode 100644 index 00000000..c4b24f21 --- /dev/null +++ b/docs/~/Controller.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Controller.prototype.initialize.html b/docs/~/Controller.prototype.initialize.html new file mode 100644 index 00000000..86757e9e --- /dev/null +++ b/docs/~/Controller.prototype.initialize.html @@ -0,0 +1,177 @@ + + + + Controller.prototype.initialize - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Controller.prototype.initialize +
+ + + + +
+
+ +

Initialize the controller. +Literally does nothing at this moment except exist to prevent errors.

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.prototype.loadComponent.html b/docs/~/Controller.prototype.loadComponent.html new file mode 100644 index 00000000..ab38a0c7 --- /dev/null +++ b/docs/~/Controller.prototype.loadComponent.html @@ -0,0 +1,251 @@ + + + + Controller.prototype.loadComponent - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Controller.prototype.loadComponent +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ name: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.prototype.render.html b/docs/~/Controller.prototype.render.html new file mode 100644 index 00000000..f8f1c644 --- /dev/null +++ b/docs/~/Controller.prototype.render.html @@ -0,0 +1,178 @@ + + + + Controller.prototype.render - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Controller.prototype.render +
+ + + + +
+
+ +

Render the page output +Will try to decide the best way of doing it based on the MIME set

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +

Promise

+
+
+
+
+
+
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.prototype.set.html b/docs/~/Controller.prototype.set.html new file mode 100644 index 00000000..c81482cc --- /dev/null +++ b/docs/~/Controller.prototype.set.html @@ -0,0 +1,303 @@ + + + + Controller.prototype.set - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Controller.prototype.set +
+ + + + +
+
+ +

Set a view variable

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+ + + + + + + + + + +
+ value: string | number | unknown + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/Controller.prototype.type.html b/docs/~/Controller.prototype.type.html new file mode 100644 index 00000000..af81df76 --- /dev/null +++ b/docs/~/Controller.prototype.type.html @@ -0,0 +1,255 @@ + + + + Controller.prototype.type - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Controller.prototype.type +
+ + + + +
+
+ +

Set the 'Content-Type' header

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+
optional
+
value: string = text/html + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Controller } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.html b/docs/~/CouchDB.html new file mode 100644 index 00000000..cad74240 --- /dev/null +++ b/docs/~/CouchDB.html @@ -0,0 +1,739 @@ + + + + CouchDB - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class CouchDB +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
CouchDB(host?: string, database: string, auth?: Auth) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+ + + + + + + + + + +
+
writeonly
+
password: string + +
+ + + + +

Update the password for this instance. +This does not update the password on the server.

+
+
+ + + + + + + + + + +
+
writeonly
+
username: string + +
+ + + + +

Update the username for this instance. +This does not update the username on the server.

+
+
+ + + + + + + + + + +
+
private
+
auth: string + +
+ + + + +
+
+
+
+ + + + + + + + + + +
+ delete(id: string, revision: string): Promise<CouchResponse> + + + + + + +

Delete a document from the database. +TODO: Automatically find revision.

+
+
+ + + + + + + + + + +
+ get(id: string): Promise<CouchResponse> + + + + + + +

Get a document from the database.

+
+
+ + + + + + + + + + +
+ insert(data: any): Promise<CouchResponse> + + + + + + +

Insert a document into the database.

+

Any document passed to the method will be attempted to insert "as-is". +The more convenient "CouchDB.upsert() | CouchDB.upsert()" method should be used most of the time.

+
+
+ + + + + + + + + + +
+ raw(endpoint: string, body?: any, overrides?: CouchOverrides): Promise<CouchResponse> + + + + + + +

Main request handler. +This method is used for most of our other methods as well.

+
+
+ + + + + + + + + + +
+ update(id: string, revision: string, data: any): Promise<CouchResponse> + + + + + + +

Update a document in the database.

+

This is only useful if you know the latest revision. +The more convenient "CouchDB.upsert() | CouchDB.upsert()" should be used most of the time.

+
+
+ + + + + + + + + + +
+ upsert(id: string, data: any): Promise<CouchResponse> + + + + + + +

Update or insert a document into the database. +This method will automatically check if an existing document exists and try to update it. +If no document exists, it will be created instead.

+
+
+ + + + + + + + + + +
+ viewDesign(design: string, view: string, partition: string): Promise<CouchResponse> + + + + + + +

Execute a view design

+
+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.auth.html b/docs/~/CouchDB.prototype.auth.html new file mode 100644 index 00000000..3f187383 --- /dev/null +++ b/docs/~/CouchDB.prototype.auth.html @@ -0,0 +1,156 @@ + + + + CouchDB.prototype.auth - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.delete.html b/docs/~/CouchDB.prototype.delete.html new file mode 100644 index 00000000..3f68753d --- /dev/null +++ b/docs/~/CouchDB.prototype.delete.html @@ -0,0 +1,384 @@ + + + + CouchDB.prototype.delete - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CouchDB.prototype.delete +
+ + + + +
+
+ +

Delete a document from the database. +TODO: Automatically find revision.

+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
+
+const couchdb = new CouchDB(...);
+const existing = await couchdb.get('my-key');
+if(existing.status === 404) return;
+const resp = await couchdb.delete('my-key', existing.data['_rev']);
+
+if(resp.status !== 200) {
+  // Handle deletion error
+}
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ id: string + + + + + + +
+
+ + + + + + + + + + +
+ revision: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<CouchResponse> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.get.html b/docs/~/CouchDB.prototype.get.html new file mode 100644 index 00000000..dca75a15 --- /dev/null +++ b/docs/~/CouchDB.prototype.get.html @@ -0,0 +1,328 @@ + + + + CouchDB.prototype.get - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CouchDB.prototype.get +
+ + + + +
+
+ +

Get a document from the database.

+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
+
+const couchdb = new CouchDB(...);
+const existing = await couchdb.get('my-key');
+
+if(existing.status === 404) {
+  // Handle non-existing document
+}
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ id: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<CouchResponse> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.html b/docs/~/CouchDB.prototype.html new file mode 100644 index 00000000..39b9f4ea --- /dev/null +++ b/docs/~/CouchDB.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/CouchDB.prototype.insert.html b/docs/~/CouchDB.prototype.insert.html new file mode 100644 index 00000000..6e777bbf --- /dev/null +++ b/docs/~/CouchDB.prototype.insert.html @@ -0,0 +1,336 @@ + + + + CouchDB.prototype.insert - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CouchDB.prototype.insert +
+ + + + +
+
+ +

Insert a document into the database.

+

Any document passed to the method will be attempted to insert "as-is". +The more convenient "CouchDB.upsert() | CouchDB.upsert()" method should be used most of the time.

+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
+
+const couchdb = new CouchDB(...);
+const resp = await couchdb.insert({
+  '_id': 'my-key',
+  'data': 'my-data',
+});
+
+if(resp.status !== 201) {
+  // Handle insert error
+}
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ data: any + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<CouchResponse> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.password.html b/docs/~/CouchDB.prototype.password.html new file mode 100644 index 00000000..a5ed3074 --- /dev/null +++ b/docs/~/CouchDB.prototype.password.html @@ -0,0 +1,321 @@ + + + + CouchDB.prototype.password - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CouchDB.prototype.password +
+ + + + +
+
+ +

Update the password for this instance. +This does not update the password on the server.

+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
+
+const couchdb = new CouchDB();
+couchdb.password = 'lamepassword';
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ password: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.raw.html b/docs/~/CouchDB.prototype.raw.html new file mode 100644 index 00000000..65e73718 --- /dev/null +++ b/docs/~/CouchDB.prototype.raw.html @@ -0,0 +1,419 @@ + + + + CouchDB.prototype.raw - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CouchDB.prototype.raw +
+ + + + +
+
+ +

Main request handler. +This method is used for most of our other methods as well.

+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
// TODO: Write example
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ endpoint: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
body: any = null + +
+ + + + +
+
+ + + + + + + + + + +
+
optional
+
overrides: CouchOverrides = [UNSUPPORTED] + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<CouchResponse> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.update.html b/docs/~/CouchDB.prototype.update.html new file mode 100644 index 00000000..06115c28 --- /dev/null +++ b/docs/~/CouchDB.prototype.update.html @@ -0,0 +1,432 @@ + + + + CouchDB.prototype.update - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CouchDB.prototype.update +
+ + + + +
+
+ +

Update a document in the database.

+

This is only useful if you know the latest revision. +The more convenient "CouchDB.upsert() | CouchDB.upsert()" should be used most of the time.

+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
+
+const couchdb = new CouchDB(...);
+const resp = await couchdb.update(`my-key`, '1-abcdef', 'my-data');
+
+if(resp.status !== 201) {
+  // Handle update error
+}
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ id: string + + + + + + +
+
+ + + + + + + + + + +
+ revision: string + + + + + + +
+
+ + + + + + + + + + +
+ data: any + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<CouchResponse> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.upsert.html b/docs/~/CouchDB.prototype.upsert.html new file mode 100644 index 00000000..17469575 --- /dev/null +++ b/docs/~/CouchDB.prototype.upsert.html @@ -0,0 +1,381 @@ + + + + CouchDB.prototype.upsert - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CouchDB.prototype.upsert +
+ + + + +
+
+ +

Update or insert a document into the database. +This method will automatically check if an existing document exists and try to update it. +If no document exists, it will be created instead.

+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
+
+const couchdb = new CouchDB(...);
+const resp = await couchdb.upsert(`my-key`, 'my-data');
+
+if(resp.status !== 201) {
+  // Handle upsert error
+}
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ id: string + + + + + + +
+
+ + + + + + + + + + +
+ data: any + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<CouchResponse> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.username.html b/docs/~/CouchDB.prototype.username.html new file mode 100644 index 00000000..da94c202 --- /dev/null +++ b/docs/~/CouchDB.prototype.username.html @@ -0,0 +1,321 @@ + + + + CouchDB.prototype.username - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CouchDB.prototype.username +
+ + + + +
+
+ +

Update the username for this instance. +This does not update the username on the server.

+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
+
+const couchdb = new CouchDB();
+couchdb.username = 'couchuser';
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ username: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/CouchDB.prototype.viewDesign.html b/docs/~/CouchDB.prototype.viewDesign.html new file mode 100644 index 00000000..cee42b7e --- /dev/null +++ b/docs/~/CouchDB.prototype.viewDesign.html @@ -0,0 +1,428 @@ + + + + CouchDB.prototype.viewDesign - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method CouchDB.prototype.viewDesign +
+ + + + +
+
+ +

Execute a view design

+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
+
+const couchdb = new CouchDB(...);
+const resp = await couchdb.viewDesign('my-design', 'my-view', 'my-partition');
+if(resp.status !== 200) {
+  // Handle view error
+}
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ design: string + + + + + + +
+
+ + + + + + + + + + +
+ view: string + + + + + + +
+
+ + + + + + + + + + +
+ partition: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<CouchResponse> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { CouchDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/Cron.Cron.html b/docs/~/Cron.Cron.html new file mode 100644 index 00000000..66f6be69 --- /dev/null +++ b/docs/~/Cron.Cron.html @@ -0,0 +1,81 @@ + + + + Cron.Cron - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ variable Cron.Cron +
+ + + + +
+
+
+
+
+

Usage

import { Cron } from ".";
+const { Cron } = Cron;
+
+
+
+
+ + diff --git a/docs/~/Cron.html b/docs/~/Cron.html new file mode 100644 index 00000000..be8af1ec --- /dev/null +++ b/docs/~/Cron.html @@ -0,0 +1,379 @@ + + + + Cron - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ function Cron +
+ + + + +
+
+ +

Cron entrypoint

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ pattern + + + + + + +
    +
  • Input pattern, input date, or input ISO 8601 time string
  • +
+
+
+ + + + + + + + + + +
+
optional
+
fnOrOptions1 + +
+ + + + +
    +
  • Options or function to be run each iteration of pattern
  • +
+
+
+ + + + + + + + + + +
+
optional
+
fnOrOptions2 + +
+ + + + +
    +
  • Options or function to be run each iteration of pattern
  • +
+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Cron } from ".";
+
+
+
+
+ + diff --git a/docs/~/DEFAULT_OPTS.html b/docs/~/DEFAULT_OPTS.html new file mode 100644 index 00000000..f129f071 --- /dev/null +++ b/docs/~/DEFAULT_OPTS.html @@ -0,0 +1,158 @@ + + + + DEFAULT_OPTS - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { DEFAULT_OPTS } from ".";
+
+
+
+
+ + diff --git a/docs/~/Druid.html b/docs/~/Druid.html new file mode 100644 index 00000000..52a29744 --- /dev/null +++ b/docs/~/Druid.html @@ -0,0 +1,415 @@ + + + + Druid - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Druid +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
Druid(host: string) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+ + + + + + + + + + +
+
writeonly
+
setSpec: any + +
+ + + + +
+
+ + + + + + + + + + +
+
readonly
+
getSpec: any + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
spec: any + +
+ + + + +
+
+
+
+ + + + + + + + + + +
+ create(): Promise<Response> + + + + + + +

Create a new task in Apache Druid

+
+
+
+
+
+
+
+

Usage

import { Druid } from ".";
+
+
+
+
+ + diff --git a/docs/~/Druid.prototype.create.html b/docs/~/Druid.prototype.create.html new file mode 100644 index 00000000..f45e11ca --- /dev/null +++ b/docs/~/Druid.prototype.create.html @@ -0,0 +1,177 @@ + + + + Druid.prototype.create - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Druid.prototype.create +
+ + + + +
+
+ +

Create a new task in Apache Druid

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<Response> + + + + + + +

Promise

+
+
+
+
+
+
+
+
+

Usage

import { Druid } from ".";
+
+
+
+
+ + diff --git a/docs/~/Druid.prototype.getSpec.html b/docs/~/Druid.prototype.getSpec.html new file mode 100644 index 00000000..a1517c70 --- /dev/null +++ b/docs/~/Druid.prototype.getSpec.html @@ -0,0 +1,175 @@ + + + + Druid.prototype.getSpec - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Druid.prototype.getSpec +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Druid } from ".";
+
+
+
+
+ + diff --git a/docs/~/Druid.prototype.html b/docs/~/Druid.prototype.html new file mode 100644 index 00000000..c62f99d2 --- /dev/null +++ b/docs/~/Druid.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Druid.prototype.setSpec.html b/docs/~/Druid.prototype.setSpec.html new file mode 100644 index 00000000..b395eac1 --- /dev/null +++ b/docs/~/Druid.prototype.setSpec.html @@ -0,0 +1,251 @@ + + + + Druid.prototype.setSpec - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Druid.prototype.setSpec +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ spec: any + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Druid } from ".";
+
+
+
+
+ + diff --git a/docs/~/Druid.prototype.spec.html b/docs/~/Druid.prototype.spec.html new file mode 100644 index 00000000..5a8f6537 --- /dev/null +++ b/docs/~/Druid.prototype.spec.html @@ -0,0 +1,156 @@ + + + + Druid.prototype.spec - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Druid } from ".";
+
+
+
+
+ + diff --git a/docs/~/ErrorCodes.html b/docs/~/ErrorCodes.html new file mode 100644 index 00000000..70975f40 --- /dev/null +++ b/docs/~/ErrorCodes.html @@ -0,0 +1,1074 @@ + + + + ErrorCodes - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ enum ErrorCodes +
+ + + + +
+
+ + + + + + + + + + +
+ DEPRECATED_FUNCTION_CALL = 1 + + + + + + +
+
+ + + + + + + + + + +
+ FILE_READ_GENERIC = 528 + + + + + + +
+
+ + + + + + + + + + +
+ FILE_READ_NOT_FOUND = 529 + + + + + + +
+
+ + + + + + + + + + +
+ FILE_READ_NO_PERM = 530 + + + + + + +
+
+ + + + + + + + + + +
+ FILE_WRITE_GENERIC = 544 + + + + + + +
+
+ + + + + + + + + + +
+ FILE_WRITE_NOT_FOUND = 545 + + + + + + +
+
+ + + + + + + + + + +
+ FILE_WRITE_NO_PERM = 546 + + + + + + +
+
+ + + + + + + + + + +
+ UNKNOWN_ERROR = 0 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_BAD_GATEWAY = 3147010 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_BAD_REQUEST = 3146752 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_FORBIDDEN = 3146755 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_GATEWAY_TIMEOUT = 3147012 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_INTERNAL_SERVER_ERROR = 3147008 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_METHOD_NOT_ALLOWED = 3146757 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_NOT_FOUND = 3146756 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_REQUEST_TIMEOUT = 3146760 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_SERVICE_UNAVAILABLE = 3147011 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP_TOO_MANY_REQUESTS = 3146793 + + + + + + +
+
+ + + + + + + + + + +
+ UPSTREAM_HTTP__UNAUTHORIZED = 3146753 + + + + + + +
+
+
+
+
+
+
+

Usage

import { ErrorCodes } from ".";
+
+
+
+
+ + diff --git a/docs/~/Events.add.html b/docs/~/Events.add.html new file mode 100644 index 00000000..601ac03b --- /dev/null +++ b/docs/~/Events.add.html @@ -0,0 +1,251 @@ + + + + Events.add - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Events.add +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ event: IEvent + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Events } from ".";
+
+
+
+
+ + diff --git a/docs/~/Events.dispatch.html b/docs/~/Events.dispatch.html new file mode 100644 index 00000000..e05fc1d6 --- /dev/null +++ b/docs/~/Events.dispatch.html @@ -0,0 +1,252 @@ + + + + Events.dispatch - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Events.dispatch +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ event: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
data: any = [UNSUPPORTED] + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Events } from ".";
+
+
+
+
+ + diff --git a/docs/~/Events.getEvents.html b/docs/~/Events.getEvents.html new file mode 100644 index 00000000..f0b4b31f --- /dev/null +++ b/docs/~/Events.getEvents.html @@ -0,0 +1,124 @@ + + + + Events.getEvents - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Events.getEvents +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Events } from ".";
+
+
+
+
+ + diff --git a/docs/~/Events.getHandler.html b/docs/~/Events.getHandler.html new file mode 100644 index 00000000..a83d7ffe --- /dev/null +++ b/docs/~/Events.getHandler.html @@ -0,0 +1,200 @@ + + + + Events.getHandler - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Events.getHandler +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ name: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Events } from ".";
+
+
+
+
+ + diff --git a/docs/~/Events.handlers.html b/docs/~/Events.handlers.html new file mode 100644 index 00000000..ae0c77b7 --- /dev/null +++ b/docs/~/Events.handlers.html @@ -0,0 +1,156 @@ + + + + Events.handlers - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Events } from ".";
+
+
+
+
+ + diff --git a/docs/~/Events.html b/docs/~/Events.html new file mode 100644 index 00000000..4e37f837 --- /dev/null +++ b/docs/~/Events.html @@ -0,0 +1,438 @@ + + + + Events - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Events +
+ + + + +
+
+

+ + + + + + + + + + +Static Properties

+ + + + + + + + + + +
+
private
+
handlers: any + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
list: IEvent[] + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Static Methods

+ + + + + + + + + + +
+ add(event: IEvent): Promise<void> + + + + + + +
+
+ + + + + + + + + + +
+ dispatch(event: string, data?: any) + + + + + + +
+ + +
+
+
+
+
+
+

Usage

import { Events } from ".";
+
+
+
+
+ + diff --git a/docs/~/Events.list.html b/docs/~/Events.list.html new file mode 100644 index 00000000..3b63cc1b --- /dev/null +++ b/docs/~/Events.list.html @@ -0,0 +1,156 @@ + + + + Events.list - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Events } from ".";
+
+
+
+
+ + diff --git a/docs/~/Events.prototype.html b/docs/~/Events.prototype.html new file mode 100644 index 00000000..9993d256 --- /dev/null +++ b/docs/~/Events.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/ExclusionConfig.directories.html b/docs/~/ExclusionConfig.directories.html new file mode 100644 index 00000000..5936a64b --- /dev/null +++ b/docs/~/ExclusionConfig.directories.html @@ -0,0 +1,156 @@ + + + + ExclusionConfig.directories - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { type ExclusionConfig } from ".";
+
+
+
+
+ + diff --git a/docs/~/ExclusionConfig.files.html b/docs/~/ExclusionConfig.files.html new file mode 100644 index 00000000..94ef2aa3 --- /dev/null +++ b/docs/~/ExclusionConfig.files.html @@ -0,0 +1,156 @@ + + + + ExclusionConfig.files - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { type ExclusionConfig } from ".";
+
+
+
+
+ + diff --git a/docs/~/ExclusionConfig.html b/docs/~/ExclusionConfig.html new file mode 100644 index 00000000..07bc1105 --- /dev/null +++ b/docs/~/ExclusionConfig.html @@ -0,0 +1,209 @@ + + + + ExclusionConfig - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { type ExclusionConfig } from ".";
+
+
+
+
+ + diff --git a/docs/~/File.html b/docs/~/File.html new file mode 100644 index 00000000..4dec3735 --- /dev/null +++ b/docs/~/File.html @@ -0,0 +1,488 @@ + + + + File - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class File +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
File(path: string) + +
+ + + + +
+
+
+
+ + + + + + + + + + +
+ create(): Promise<void> + + + + + + +
+
+ + + + + + + + + + +
+ delete(): Promise<void> + + + + + + +
+
+ + + + + + + + + + +
+ exists(): Promise<boolean> + + + + + + +
+
+ + + + + + + + + + +
+ ext(): string + + + + + + +
+ + +
+
+
+
+
+
+

Usage

import { File } from ".";
+
+
+
+
+ + diff --git a/docs/~/File.prototype.create.html b/docs/~/File.prototype.create.html new file mode 100644 index 00000000..6a0a28b4 --- /dev/null +++ b/docs/~/File.prototype.create.html @@ -0,0 +1,175 @@ + + + + File.prototype.create - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method File.prototype.create +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { File } from ".";
+
+
+
+
+ + diff --git a/docs/~/File.prototype.delete.html b/docs/~/File.prototype.delete.html new file mode 100644 index 00000000..c8c9e8d7 --- /dev/null +++ b/docs/~/File.prototype.delete.html @@ -0,0 +1,175 @@ + + + + File.prototype.delete - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method File.prototype.delete +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { File } from ".";
+
+
+
+
+ + diff --git a/docs/~/File.prototype.exists.html b/docs/~/File.prototype.exists.html new file mode 100644 index 00000000..577dc38b --- /dev/null +++ b/docs/~/File.prototype.exists.html @@ -0,0 +1,175 @@ + + + + File.prototype.exists - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method File.prototype.exists +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<boolean> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { File } from ".";
+
+
+
+
+ + diff --git a/docs/~/File.prototype.ext.html b/docs/~/File.prototype.ext.html new file mode 100644 index 00000000..5b3a075c --- /dev/null +++ b/docs/~/File.prototype.ext.html @@ -0,0 +1,175 @@ + + + + File.prototype.ext - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method File.prototype.ext +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { File } from ".";
+
+
+
+
+ + diff --git a/docs/~/File.prototype.html b/docs/~/File.prototype.html new file mode 100644 index 00000000..75694429 --- /dev/null +++ b/docs/~/File.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/File.prototype.readFile.html b/docs/~/File.prototype.readFile.html new file mode 100644 index 00000000..2a4ac28d --- /dev/null +++ b/docs/~/File.prototype.readFile.html @@ -0,0 +1,124 @@ + + + + File.prototype.readFile - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method File.prototype.readFile +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { File } from ".";
+
+
+
+
+ + diff --git a/docs/~/File.prototype.readTextFile.html b/docs/~/File.prototype.readTextFile.html new file mode 100644 index 00000000..fc800386 --- /dev/null +++ b/docs/~/File.prototype.readTextFile.html @@ -0,0 +1,124 @@ + + + + File.prototype.readTextFile - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method File.prototype.readTextFile +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { File } from ".";
+
+
+
+
+ + diff --git a/docs/~/Folder.html b/docs/~/Folder.html new file mode 100644 index 00000000..53b0e6f6 --- /dev/null +++ b/docs/~/Folder.html @@ -0,0 +1,286 @@ + + + + Folder - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Folder } from ".";
+
+
+
+
+ + diff --git a/docs/~/Folder.prototype.create.html b/docs/~/Folder.prototype.create.html new file mode 100644 index 00000000..d22349bb --- /dev/null +++ b/docs/~/Folder.prototype.create.html @@ -0,0 +1,254 @@ + + + + Folder.prototype.create - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Folder.prototype.create +
+ + + + +
+
+ +

Create the directory if it does not exist yet.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+
optional
+
options: Deno.MkdirOptions + +
+ + + + +

Options with which to create the directory

+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Folder } from ".";
+
+
+
+
+ + diff --git a/docs/~/Folder.prototype.exists.html b/docs/~/Folder.prototype.exists.html new file mode 100644 index 00000000..81e5f65f --- /dev/null +++ b/docs/~/Folder.prototype.exists.html @@ -0,0 +1,176 @@ + + + + Folder.prototype.exists - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Folder.prototype.exists +
+ + + + +
+
+ +

Check whether the folder exists at the path.

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<boolean> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Folder } from ".";
+
+
+
+
+ + diff --git a/docs/~/Folder.prototype.html b/docs/~/Folder.prototype.html new file mode 100644 index 00000000..d76968ff --- /dev/null +++ b/docs/~/Folder.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/GraphQL.html b/docs/~/GraphQL.html new file mode 100644 index 00000000..355c2a49 --- /dev/null +++ b/docs/~/GraphQL.html @@ -0,0 +1,466 @@ + + + + GraphQL - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class GraphQL +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
GraphQL(endpoint?: string) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+ + + + + + + + + + +
+
private
+
_query: string + +
+ + + + +
+ +
+
+
+ + + + + + + + + + +
+ addVariable(key: string, value: string): GraphQL + + + + + + +

Add a variable to our variables object

+
+ +
+ + + + + + + + + + +
+ setQuery(query: string): GraphQL + + + + + + +

Set our query string

+
+
+
+
+
+
+
+

Usage

import { GraphQL } from ".";
+
+
+
+
+ + diff --git a/docs/~/GraphQL.prototype._query.html b/docs/~/GraphQL.prototype._query.html new file mode 100644 index 00000000..3fb4ee03 --- /dev/null +++ b/docs/~/GraphQL.prototype._query.html @@ -0,0 +1,156 @@ + + + + GraphQL.prototype._query - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { GraphQL } from ".";
+
+
+
+
+ + diff --git a/docs/~/GraphQL.prototype._variables.html b/docs/~/GraphQL.prototype._variables.html new file mode 100644 index 00000000..8dc57af4 --- /dev/null +++ b/docs/~/GraphQL.prototype._variables.html @@ -0,0 +1,79 @@ + + + + GraphQL.prototype._variables - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ property GraphQL.prototype._variables +
+ + + + +
+
+
+
+
+

Usage

import { GraphQL } from ".";
+
+
+
+
+ + diff --git a/docs/~/GraphQL.prototype.addVariable.html b/docs/~/GraphQL.prototype.addVariable.html new file mode 100644 index 00000000..0912f362 --- /dev/null +++ b/docs/~/GraphQL.prototype.addVariable.html @@ -0,0 +1,304 @@ + + + + GraphQL.prototype.addVariable - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method GraphQL.prototype.addVariable +
+ + + + +
+
+ +

Add a variable to our variables object

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ key: string + + + + + + +
+
+ + + + + + + + + + +
+ value: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +

The instance of this class

+
+
+
+
+
+
+
+
+

Usage

import { GraphQL } from ".";
+
+
+
+
+ + diff --git a/docs/~/GraphQL.prototype.execute.html b/docs/~/GraphQL.prototype.execute.html new file mode 100644 index 00000000..f7b44327 --- /dev/null +++ b/docs/~/GraphQL.prototype.execute.html @@ -0,0 +1,124 @@ + + + + GraphQL.prototype.execute - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method GraphQL.prototype.execute +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { GraphQL } from ".";
+
+
+
+
+ + diff --git a/docs/~/GraphQL.prototype.html b/docs/~/GraphQL.prototype.html new file mode 100644 index 00000000..55bc4c5b --- /dev/null +++ b/docs/~/GraphQL.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/GraphQL.prototype.setQuery.html b/docs/~/GraphQL.prototype.setQuery.html new file mode 100644 index 00000000..3cd577dd --- /dev/null +++ b/docs/~/GraphQL.prototype.setQuery.html @@ -0,0 +1,253 @@ + + + + GraphQL.prototype.setQuery - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method GraphQL.prototype.setQuery +
+ + + + +
+
+ +

Set our query string

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ query: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +

The instance of this class

+
+
+
+
+
+
+
+
+

Usage

import { GraphQL } from ".";
+
+
+
+
+ + diff --git a/docs/~/Hash.html b/docs/~/Hash.html new file mode 100644 index 00000000..e2c5c9aa --- /dev/null +++ b/docs/~/Hash.html @@ -0,0 +1,363 @@ + + + + Hash - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Hash } from ".";
+
+
+
+
+ + diff --git a/docs/~/Hash.prototype.digest.html b/docs/~/Hash.prototype.digest.html new file mode 100644 index 00000000..ae829173 --- /dev/null +++ b/docs/~/Hash.prototype.digest.html @@ -0,0 +1,289 @@ + + + + Hash.prototype.digest - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Hash.prototype.digest +
+ + + + +
+
+ +

Digest the input

+
+
+ + + + + + + + + + +
+ +

Basic usage

+
+
import { Hash } from "https://deno.land/x/chomp/security/hash.ts";
+
+const hash = new Hash("some data");
+await hash.digest();
+console.log(hash.hex());
+
+
+
+
+
+ + + + + + + + + + +
+ +

Using BLAKE2B384

+
+
import { Hash, Algorithms } from "https://deno.land/x/chomp/security/hash.ts";
+
+const hash = new Hash("some data", Algorithms.BLAKE2B384);
+await hash.digest();
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Hash } from ".";
+
+
+
+
+ + diff --git a/docs/~/Hash.prototype.hex.html b/docs/~/Hash.prototype.hex.html new file mode 100644 index 00000000..593ce811 --- /dev/null +++ b/docs/~/Hash.prototype.hex.html @@ -0,0 +1,195 @@ + + + + Hash.prototype.hex - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Hash.prototype.hex +
+ + + + +
+
+ +

Digest the input

+
+
+ + + + + + + + + + +
+ +

Basic usage

+
+
import { Hash } from "https://deno.land/x/chomp/security/hash.ts";
+
+const hash = new Hash("some data");
+await hash.digest();
+console.log(hash.hex());
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Hash } from ".";
+
+
+
+
+ + diff --git a/docs/~/Hash.prototype.html b/docs/~/Hash.prototype.html new file mode 100644 index 00000000..dbe99667 --- /dev/null +++ b/docs/~/Hash.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Hash.prototype.result.html b/docs/~/Hash.prototype.result.html new file mode 100644 index 00000000..d5593336 --- /dev/null +++ b/docs/~/Hash.prototype.result.html @@ -0,0 +1,156 @@ + + + + Hash.prototype.result - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Hash } from ".";
+
+
+
+
+ + diff --git a/docs/~/INSECURE_ALGORITHMS.html b/docs/~/INSECURE_ALGORITHMS.html new file mode 100644 index 00000000..4ca39a8a --- /dev/null +++ b/docs/~/INSECURE_ALGORITHMS.html @@ -0,0 +1,157 @@ + + + + INSECURE_ALGORITHMS - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { INSECURE_ALGORITHMS } from ".";
+
+
+
+
+ + diff --git a/docs/~/Inflector.camelize.html b/docs/~/Inflector.camelize.html new file mode 100644 index 00000000..b6f624b4 --- /dev/null +++ b/docs/~/Inflector.camelize.html @@ -0,0 +1,305 @@ + + + + Inflector.camelize - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Inflector.camelize +
+ + + + +
+
+ +

Turn a string into camelCase

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ input: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
delimiter: string = _ + +
+ + + + +

Optional delimiter by which to split the string

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Inflector } from ".";
+
+
+
+
+ + diff --git a/docs/~/Inflector.html b/docs/~/Inflector.html new file mode 100644 index 00000000..f961fc56 --- /dev/null +++ b/docs/~/Inflector.html @@ -0,0 +1,367 @@ + + + + Inflector - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Inflector +
+ + + + +

Idea and code primarily based on CakePHP's code.

+
+
+

+ + + + + + + + + + +Static Methods

+ + + + + + + + + + +
+ camelize(input: string, delimiter?: string): string + + + + + + +

Turn a string into camelCase

+
+
+ + + + + + + + + + +
+ humanize(input: string, delimiter?: string): string + + + + + + +

Return the input lower_case_delimited_string as "A Human Readable String". +(Underscores are replaced by spaces and capitalized following words.)

+
+
+ + + + + + + + + + +
+ lcfirst(input: string): string + + + + + + +

Return input string with first character lowercased.

+
+
+ + + + + + + + + + +
+ pascalize(input: string, delimiter?: string): string + + + + + + +

Turn a string into PascalCase.

+
+
+ + + + + + + + + + +
+ ucfirst(input: string): string + + + + + + +

Return input string with first character uppercased.

+
+
+
+
+
+
+
+

Usage

import { Inflector } from ".";
+
+
+
+
+ + diff --git a/docs/~/Inflector.humanize.html b/docs/~/Inflector.humanize.html new file mode 100644 index 00000000..6944ae52 --- /dev/null +++ b/docs/~/Inflector.humanize.html @@ -0,0 +1,305 @@ + + + + Inflector.humanize - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Inflector.humanize +
+ + + + +
+
+ +

Return the input lower_case_delimited_string as "A Human Readable String". +(Underscores are replaced by spaces and capitalized following words.)

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ input: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
delimiter: string = _ + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Inflector } from ".";
+
+
+
+
+ + diff --git a/docs/~/Inflector.lcfirst.html b/docs/~/Inflector.lcfirst.html new file mode 100644 index 00000000..349fde4a --- /dev/null +++ b/docs/~/Inflector.lcfirst.html @@ -0,0 +1,252 @@ + + + + Inflector.lcfirst - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Inflector.lcfirst +
+ + + + +
+
+ +

Return input string with first character lowercased.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ input: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Inflector } from ".";
+
+
+
+
+ + diff --git a/docs/~/Inflector.pascalize.html b/docs/~/Inflector.pascalize.html new file mode 100644 index 00000000..4f94149f --- /dev/null +++ b/docs/~/Inflector.pascalize.html @@ -0,0 +1,305 @@ + + + + Inflector.pascalize - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Inflector.pascalize +
+ + + + +
+
+ +

Turn a string into PascalCase.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ input: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
delimiter: string = _ + +
+ + + + +

Optional delimiter by which to split the string

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Inflector } from ".";
+
+
+
+
+ + diff --git a/docs/~/Inflector.prototype.html b/docs/~/Inflector.prototype.html new file mode 100644 index 00000000..a8910a9f --- /dev/null +++ b/docs/~/Inflector.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Inflector.ucfirst.html b/docs/~/Inflector.ucfirst.html new file mode 100644 index 00000000..f98d82ab --- /dev/null +++ b/docs/~/Inflector.ucfirst.html @@ -0,0 +1,252 @@ + + + + Inflector.ucfirst - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Inflector.ucfirst +
+ + + + +
+
+ +

Return input string with first character uppercased.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ input: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Inflector } from ".";
+
+
+
+
+ + diff --git a/docs/~/InfluxDB.html b/docs/~/InfluxDB.html new file mode 100644 index 00000000..63eb3a6a --- /dev/null +++ b/docs/~/InfluxDB.html @@ -0,0 +1,362 @@ + + + + InfluxDB - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class InfluxDB +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
InfluxDB(url: string, token: string) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+ + + + + + + + + + +
+
private
+
_api: Api + +
+ + + + +
+
+
+
+ + + + + + + + + + +
+ setApi(org: string, bucket: string, precision?: Precision): this + + + + + + +
+
+ + + + + + + + + + +
+ write(data: Point | Point[]): Promise<boolean> + + + + + + +

Write our datapoint(s) to InfluxDB

+
+
+
+
+
+
+
+

Usage

import { InfluxDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/InfluxDB.prototype._api.html b/docs/~/InfluxDB.prototype._api.html new file mode 100644 index 00000000..51f83cb5 --- /dev/null +++ b/docs/~/InfluxDB.prototype._api.html @@ -0,0 +1,156 @@ + + + + InfluxDB.prototype._api - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { InfluxDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/InfluxDB.prototype.html b/docs/~/InfluxDB.prototype.html new file mode 100644 index 00000000..9fd60992 --- /dev/null +++ b/docs/~/InfluxDB.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/InfluxDB.prototype.setApi.html b/docs/~/InfluxDB.prototype.setApi.html new file mode 100644 index 00000000..156c48bf --- /dev/null +++ b/docs/~/InfluxDB.prototype.setApi.html @@ -0,0 +1,354 @@ + + + + InfluxDB.prototype.setApi - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method InfluxDB.prototype.setApi +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ org: string + + + + + + +
+
+ + + + + + + + + + +
+ bucket: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
precision: Precision = [Precision.us] + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { InfluxDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/InfluxDB.prototype.write.html b/docs/~/InfluxDB.prototype.write.html new file mode 100644 index 00000000..ddc4997b --- /dev/null +++ b/docs/~/InfluxDB.prototype.write.html @@ -0,0 +1,252 @@ + + + + InfluxDB.prototype.write - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method InfluxDB.prototype.write +
+ + + + +
+
+ +

Write our datapoint(s) to InfluxDB

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ data: Point | Point[] + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<boolean> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { InfluxDB } from ".";
+
+
+
+
+ + diff --git a/docs/~/Logger._handlers.html b/docs/~/Logger._handlers.html new file mode 100644 index 00000000..176ab9b8 --- /dev/null +++ b/docs/~/Logger._handlers.html @@ -0,0 +1,156 @@ + + + + Logger._handlers - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Logger } from ".";
+
+
+
+
+ + diff --git a/docs/~/Logger.debug.html b/docs/~/Logger.debug.html new file mode 100644 index 00000000..daebd0c3 --- /dev/null +++ b/docs/~/Logger.debug.html @@ -0,0 +1,254 @@ + + + + Logger.debug - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Logger.debug +
+ + + + +
+
+ +

Write a debug message to the console +Only shows up when the "DEBUG" env is set to truthy

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ message: string + + + + + + +

The message to write

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Logger } from ".";
+
+
+
+
+ + diff --git a/docs/~/Logger.error.html b/docs/~/Logger.error.html new file mode 100644 index 00000000..1c17fe0a --- /dev/null +++ b/docs/~/Logger.error.html @@ -0,0 +1,307 @@ + + + + Logger.error - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Logger.error +
+ + + + +
+
+ +

Write an error message to the console. +If the "error_log" Configure item is set, will also write to file.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ message: string + + + + + + +

The message to write

+
+
+ + + + + + + + + + +
+
optional
+
stack: string | null = null + +
+ + + + +

Optional stacktrace

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Logger } from ".";
+
+
+
+
+ + diff --git a/docs/~/Logger.html b/docs/~/Logger.html new file mode 100644 index 00000000..62ca5898 --- /dev/null +++ b/docs/~/Logger.html @@ -0,0 +1,499 @@ + + + + Logger - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Logger +
+ + + + +
+
+

+ + + + + + + + + + +Static Properties

+ + + + + + + + + + +
+
private
+
_handlers: Handlers + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Static Methods

+ + + + + + + + + + +
+ debug(message: string): void + + + + + + +

Write a debug message to the console +Only shows up when the "DEBUG" env is set to truthy

+
+
+ + + + + + + + + + +
+ error(message: string, stack?: string | null): void + + + + + + +

Write an error message to the console. +If the "error_log" Configure item is set, will also write to file.

+
+
+ + + + + + + + + + +
+ info(message: string): void + + + + + + +

Write an info message to the console

+
+
+ + + + + + + + + + +
+ setHandler(level: LogLevels, handler: Function): void + + + + + + +

Override a handler app-wide.

+
+
+ + + + + + + + + + +
+ time(): string + + + + + + +

Return the current time in format. +Configurable using the "logger.timeformat" key. +Defaults to "yyyy/MM/dd HH:mm:ss" (2020/11/28 20:50:30) +https://github.com/denoland/deno_std/tree/0.77.0/datetime#datetime

+
+
+ + + + + + + + + + +
+ warning(message: string): void + + + + + + +

Write a warning message to the console

+
+
+
+
+
+
+
+

Usage

import { Logger } from ".";
+
+
+
+
+ + diff --git a/docs/~/Logger.info.html b/docs/~/Logger.info.html new file mode 100644 index 00000000..89354aa4 --- /dev/null +++ b/docs/~/Logger.info.html @@ -0,0 +1,253 @@ + + + + Logger.info - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Logger.info +
+ + + + +
+
+ +

Write an info message to the console

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ message: string + + + + + + +

The message to write

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Logger } from ".";
+
+
+
+
+ + diff --git a/docs/~/Logger.prototype.html b/docs/~/Logger.prototype.html new file mode 100644 index 00000000..e45b1963 --- /dev/null +++ b/docs/~/Logger.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Logger.setHandler.html b/docs/~/Logger.setHandler.html new file mode 100644 index 00000000..236e50e0 --- /dev/null +++ b/docs/~/Logger.setHandler.html @@ -0,0 +1,305 @@ + + + + Logger.setHandler - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Logger.setHandler +
+ + + + +
+
+ +

Override a handler app-wide.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ level: LogLevels + + + + + + +

{LogLevels}

+
+
+ + + + + + + + + + +
+ handler: Function + + + + + + +

{any}

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Logger } from ".";
+
+
+
+
+ + diff --git a/docs/~/Logger.time.html b/docs/~/Logger.time.html new file mode 100644 index 00000000..3124f34c --- /dev/null +++ b/docs/~/Logger.time.html @@ -0,0 +1,180 @@ + + + + Logger.time - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Logger.time +
+ + + + +
+
+ +

Return the current time in format. +Configurable using the "logger.timeformat" key. +Defaults to "yyyy/MM/dd HH:mm:ss" (2020/11/28 20:50:30) +https://github.com/denoland/deno_std/tree/0.77.0/datetime#datetime

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ string + + + + + + +

The formatted time

+
+
+
+
+
+
+
+
+

Usage

import { Logger } from ".";
+
+
+
+
+ + diff --git a/docs/~/Logger.warning.html b/docs/~/Logger.warning.html new file mode 100644 index 00000000..857ce18c --- /dev/null +++ b/docs/~/Logger.warning.html @@ -0,0 +1,253 @@ + + + + Logger.warning - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Logger.warning +
+ + + + +
+
+ +

Write a warning message to the console

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ message: string + + + + + + +

The message to write

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Logger } from ".";
+
+
+
+
+ + diff --git a/docs/~/Loki.html b/docs/~/Loki.html new file mode 100644 index 00000000..d5e18512 --- /dev/null +++ b/docs/~/Loki.html @@ -0,0 +1,234 @@ + + + + Loki - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Loki } from ".";
+
+
+
+
+ + diff --git a/docs/~/Loki.prototype.html b/docs/~/Loki.prototype.html new file mode 100644 index 00000000..835538bb --- /dev/null +++ b/docs/~/Loki.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Loki.prototype.send.html b/docs/~/Loki.prototype.send.html new file mode 100644 index 00000000..99600318 --- /dev/null +++ b/docs/~/Loki.prototype.send.html @@ -0,0 +1,252 @@ + + + + Loki.prototype.send - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Loki.prototype.send +
+ + + + +
+
+ +

Send a log entry to the Grafana Loki database.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ stream: LokiStream | LokiStream[] + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Loki } from ".";
+
+
+
+
+ + diff --git a/docs/~/Ntfy.html b/docs/~/Ntfy.html new file mode 100644 index 00000000..d9bd15ed --- /dev/null +++ b/docs/~/Ntfy.html @@ -0,0 +1,234 @@ + + + + Ntfy - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Ntfy } from ".";
+
+
+
+
+ + diff --git a/docs/~/Ntfy.prototype.html b/docs/~/Ntfy.prototype.html new file mode 100644 index 00000000..8322424f --- /dev/null +++ b/docs/~/Ntfy.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Ntfy.prototype.send.html b/docs/~/Ntfy.prototype.send.html new file mode 100644 index 00000000..9673ac29 --- /dev/null +++ b/docs/~/Ntfy.prototype.send.html @@ -0,0 +1,252 @@ + + + + Ntfy.prototype.send - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Ntfy.prototype.send +
+ + + + +
+
+ +

Send a notification through Ntfy

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ message: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Ntfy } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.html b/docs/~/Nut.html new file mode 100644 index 00000000..ddbae8aa --- /dev/null +++ b/docs/~/Nut.html @@ -0,0 +1,1083 @@ + + + + Nut - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Nut +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
Nut(host: string | undefined, port?: number) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+
+ + + + + + + + + + +
+
readonly
+
status: number + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
_status: number + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
callback: any + +
+ + + + +
+ +
+ + + + + + + + + + +
+
private
+
dataBuf: string + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
host: string + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
port: number + +
+ + + + +
+
+
+
+
+ + + + + + + + + + +
+ connect(): Promise<void> + + + + + + +
+
+ + + + + + + + + + +
+ getCharge(name: string | undefined): Promise<number> + + + + + + +
+
+ + + + + + + + + + +
+ getLoad(name: string | undefined): Promise<number> + + + + + + +
+
+ + + + + + + + + + +
+ getPowerLimit(name: string | undefined): Promise<number> + + + + + + +
+
+ + + + + + + + + + +
+ getRuntime(name: string | undefined): Promise<number> + + + + + + +
+
+ + + + + + + + + + +
+ getStatus(name: string | undefined): Promise<string> + + + + + + +
+
+ + + + + + + + + + +
+
private
+
onReceive(): Promise<void> + +
+ + + + +
+
+ + + + + + + + + + +
+ send(cmd: string, callback: any): Promise<void> + + + + + + +
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.UPSList.html b/docs/~/Nut.prototype.UPSList.html new file mode 100644 index 00000000..839f5967 --- /dev/null +++ b/docs/~/Nut.prototype.UPSList.html @@ -0,0 +1,124 @@ + + + + Nut.prototype.UPSList - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.UPSList +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype._status.html b/docs/~/Nut.prototype._status.html new file mode 100644 index 00000000..52fc5c10 --- /dev/null +++ b/docs/~/Nut.prototype._status.html @@ -0,0 +1,156 @@ + + + + Nut.prototype._status - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.callback.html b/docs/~/Nut.prototype.callback.html new file mode 100644 index 00000000..339beb50 --- /dev/null +++ b/docs/~/Nut.prototype.callback.html @@ -0,0 +1,156 @@ + + + + Nut.prototype.callback - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.client.html b/docs/~/Nut.prototype.client.html new file mode 100644 index 00000000..fbeeb54b --- /dev/null +++ b/docs/~/Nut.prototype.client.html @@ -0,0 +1,156 @@ + + + + Nut.prototype.client - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.close.html b/docs/~/Nut.prototype.close.html new file mode 100644 index 00000000..635ed6c7 --- /dev/null +++ b/docs/~/Nut.prototype.close.html @@ -0,0 +1,175 @@ + + + + Nut.prototype.close - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.close +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.connect.html b/docs/~/Nut.prototype.connect.html new file mode 100644 index 00000000..a16cab35 --- /dev/null +++ b/docs/~/Nut.prototype.connect.html @@ -0,0 +1,175 @@ + + + + Nut.prototype.connect - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.connect +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.dataBuf.html b/docs/~/Nut.prototype.dataBuf.html new file mode 100644 index 00000000..52d1f26a --- /dev/null +++ b/docs/~/Nut.prototype.dataBuf.html @@ -0,0 +1,156 @@ + + + + Nut.prototype.dataBuf - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.getCharge.html b/docs/~/Nut.prototype.getCharge.html new file mode 100644 index 00000000..ebdf1b5e --- /dev/null +++ b/docs/~/Nut.prototype.getCharge.html @@ -0,0 +1,251 @@ + + + + Nut.prototype.getCharge - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.getCharge +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ name: string | undefined + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<number> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.getLoad.html b/docs/~/Nut.prototype.getLoad.html new file mode 100644 index 00000000..76d644fd --- /dev/null +++ b/docs/~/Nut.prototype.getLoad.html @@ -0,0 +1,251 @@ + + + + Nut.prototype.getLoad - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.getLoad +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ name: string | undefined + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<number> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.getPowerLimit.html b/docs/~/Nut.prototype.getPowerLimit.html new file mode 100644 index 00000000..8d2737a1 --- /dev/null +++ b/docs/~/Nut.prototype.getPowerLimit.html @@ -0,0 +1,251 @@ + + + + Nut.prototype.getPowerLimit - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.getPowerLimit +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ name: string | undefined + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<number> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.getRuntime.html b/docs/~/Nut.prototype.getRuntime.html new file mode 100644 index 00000000..1183cc56 --- /dev/null +++ b/docs/~/Nut.prototype.getRuntime.html @@ -0,0 +1,251 @@ + + + + Nut.prototype.getRuntime - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.getRuntime +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ name: string | undefined + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<number> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.getStatus.html b/docs/~/Nut.prototype.getStatus.html new file mode 100644 index 00000000..bfddaf31 --- /dev/null +++ b/docs/~/Nut.prototype.getStatus.html @@ -0,0 +1,251 @@ + + + + Nut.prototype.getStatus - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.getStatus +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ name: string | undefined + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<string> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.host.html b/docs/~/Nut.prototype.host.html new file mode 100644 index 00000000..2bf7efab --- /dev/null +++ b/docs/~/Nut.prototype.host.html @@ -0,0 +1,156 @@ + + + + Nut.prototype.host - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.html b/docs/~/Nut.prototype.html new file mode 100644 index 00000000..57b9b336 --- /dev/null +++ b/docs/~/Nut.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Nut.prototype.onReceive.html b/docs/~/Nut.prototype.onReceive.html new file mode 100644 index 00000000..d54074a0 --- /dev/null +++ b/docs/~/Nut.prototype.onReceive.html @@ -0,0 +1,175 @@ + + + + Nut.prototype.onReceive - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.onReceive +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.port.html b/docs/~/Nut.prototype.port.html new file mode 100644 index 00000000..7e3cd94e --- /dev/null +++ b/docs/~/Nut.prototype.port.html @@ -0,0 +1,156 @@ + + + + Nut.prototype.port - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.send.html b/docs/~/Nut.prototype.send.html new file mode 100644 index 00000000..954eb17c --- /dev/null +++ b/docs/~/Nut.prototype.send.html @@ -0,0 +1,302 @@ + + + + Nut.prototype.send - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.send +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ cmd: string + + + + + + +
+
+ + + + + + + + + + +
+ callback: any + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/Nut.prototype.status.html b/docs/~/Nut.prototype.status.html new file mode 100644 index 00000000..6e4ead9f --- /dev/null +++ b/docs/~/Nut.prototype.status.html @@ -0,0 +1,175 @@ + + + + Nut.prototype.status - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Nut.prototype.status +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Nut } from ".";
+
+
+
+
+ + diff --git a/docs/~/PASSWORD_DEFAULT.html b/docs/~/PASSWORD_DEFAULT.html new file mode 100644 index 00000000..f96573d1 --- /dev/null +++ b/docs/~/PASSWORD_DEFAULT.html @@ -0,0 +1,81 @@ + + + + PASSWORD_DEFAULT - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ variable PASSWORD_DEFAULT +
+ + + + +

Recommended hashing algorithm for most use-cases. +May change over time to keep up with NIST approved algorithms

+
+
+
+
+
+

Usage

import { PASSWORD_DEFAULT } from ".";
+
+
+
+
+ + diff --git a/docs/~/Password.doHash.html b/docs/~/Password.doHash.html new file mode 100644 index 00000000..da03b5f6 --- /dev/null +++ b/docs/~/Password.doHash.html @@ -0,0 +1,404 @@ + + + + Password.doHash - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Password.doHash +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ input: string + + + + + + +
+
+ + + + + + + + + + +
+ algo: string + + + + + + +
+
+ + + + + + + + + + +
+ salt: string + + + + + + +
+
+ + + + + + + + + + +
+ cost: number + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<string> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Password } from ".";
+
+
+
+
+ + diff --git a/docs/~/Password.hash.html b/docs/~/Password.hash.html new file mode 100644 index 00000000..fc39ca28 --- /dev/null +++ b/docs/~/Password.hash.html @@ -0,0 +1,357 @@ + + + + Password.hash - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Password.hash +
+ + + + +
+
+ +

Hash the password using the specified password algorithm

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ password: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
algo: Algorithms = PASSWORD_DEFAULT + +
+ + + + +
+
+ + + + + + + + + + +
+
optional
+
options: PasswordOptions = DEFAULT_OPTS + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<string> + + + + + + +

Hash string containing algo, cost, salt and hash

+
+
+
+
+
+
+
+
+

Usage

import { Password } from ".";
+
+
+
+
+ + diff --git a/docs/~/Password.html b/docs/~/Password.html new file mode 100644 index 00000000..aa2b5122 --- /dev/null +++ b/docs/~/Password.html @@ -0,0 +1,260 @@ + + + + Password - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Password } from ".";
+
+
+
+
+ + diff --git a/docs/~/Password.prototype.html b/docs/~/Password.prototype.html new file mode 100644 index 00000000..acecbf2a --- /dev/null +++ b/docs/~/Password.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Password.verify.html b/docs/~/Password.verify.html new file mode 100644 index 00000000..c0ae855d --- /dev/null +++ b/docs/~/Password.verify.html @@ -0,0 +1,305 @@ + + + + Password.verify - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Password.verify +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ password: string + + + + + + +

Input password to check against

+
+
+ + + + + + + + + + +
+ hash: string + + + + + + +

Hash string input from Password.hash()

+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<boolean> + + + + + + +

Promise Whether the password was valid or not

+
+
+
+
+
+
+
+
+

Usage

import { Password } from ".";
+
+
+
+
+ + diff --git a/docs/~/PasswordOptions.allowInsecure.html b/docs/~/PasswordOptions.allowInsecure.html new file mode 100644 index 00000000..d5aebcd5 --- /dev/null +++ b/docs/~/PasswordOptions.allowInsecure.html @@ -0,0 +1,156 @@ + + + + PasswordOptions.allowInsecure - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { type PasswordOptions } from ".";
+
+
+
+
+ + diff --git a/docs/~/PasswordOptions.cost.html b/docs/~/PasswordOptions.cost.html new file mode 100644 index 00000000..ee61eb69 --- /dev/null +++ b/docs/~/PasswordOptions.cost.html @@ -0,0 +1,156 @@ + + + + PasswordOptions.cost - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { type PasswordOptions } from ".";
+
+
+
+
+ + diff --git a/docs/~/PasswordOptions.html b/docs/~/PasswordOptions.html new file mode 100644 index 00000000..2a72ae0c --- /dev/null +++ b/docs/~/PasswordOptions.html @@ -0,0 +1,210 @@ + + + + PasswordOptions - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { type PasswordOptions } from ".";
+
+
+
+
+ + diff --git a/docs/~/QueryParameters.html b/docs/~/QueryParameters.html new file mode 100644 index 00000000..bb7b2dc8 --- /dev/null +++ b/docs/~/QueryParameters.html @@ -0,0 +1,128 @@ + + + + QueryParameters - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { type QueryParameters } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.html b/docs/~/Queue.html new file mode 100644 index 00000000..93cf250b --- /dev/null +++ b/docs/~/Queue.html @@ -0,0 +1,735 @@ + + + + Queue - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Queue +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
Queue(scheduler?: Scheduler) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+ + + + + + + + + + +
+
readonly
+
count: number + +
+ + + + +

Get the number of items contained in the Queue

+
+
+ + + + + + + + + + +
+
readonly
+
dump: QueueItem[] + +
+ + + + +

Return all the items in the queue

+
+
+ + + + + + + + + + +
+
readonly
+
isEmpty: boolean + +
+ + + + +

Check whether the Queue has any items

+
+
+ + + + + + + + + + +
+
readonly
+
next: QueueItem | null + +
+ + + + +

Get the next item from the queue. +Unlike the Queue#peek() method, this does remove the item.

+
+
+ + + + + + + + + + +
+
readonly
+
peek: QueueItem | null + +
+ + + + +

Get the next item from the queue. +Unlike the Queue#next() method, this does not remove the item.

+
+
+ + + + + + + + + + +
+
private
+
items: QueueItem[] + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
readonly
+
scheduler: Scheduler + +
+ + + + +
+
+
+
+ + + + + + + + + + +
+ add(item: QueueItem): void + + + + + + +

Add an item to the queue based on the scheduler used

+
+
+ + + + + + + + + + +
+ clear(): void + + + + + + +

Remove all items from the Queue

+
+
+ + + + + + + + + + +
+ contains(item: QueueItem): boolean + + + + + + +

Check whether the queue already contains an identical item

+
+
+
+
+
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.add.html b/docs/~/Queue.prototype.add.html new file mode 100644 index 00000000..50a91f2b --- /dev/null +++ b/docs/~/Queue.prototype.add.html @@ -0,0 +1,253 @@ + + + + Queue.prototype.add - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Queue.prototype.add +
+ + + + +
+
+ +

Add an item to the queue based on the scheduler used

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ item: QueueItem + + + + + + +

Item to add to the queue

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.clear.html b/docs/~/Queue.prototype.clear.html new file mode 100644 index 00000000..160ceab8 --- /dev/null +++ b/docs/~/Queue.prototype.clear.html @@ -0,0 +1,177 @@ + + + + Queue.prototype.clear - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Queue.prototype.clear +
+ + + + +
+
+ +

Remove all items from the Queue

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ void + + + + + + +

void

+
+
+
+
+
+
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.contains.html b/docs/~/Queue.prototype.contains.html new file mode 100644 index 00000000..30eb7699 --- /dev/null +++ b/docs/~/Queue.prototype.contains.html @@ -0,0 +1,253 @@ + + + + Queue.prototype.contains - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Queue.prototype.contains +
+ + + + +
+
+ +

Check whether the queue already contains an identical item

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ item: QueueItem + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ boolean + + + + + + +

boolean

+
+
+
+
+
+
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.count.html b/docs/~/Queue.prototype.count.html new file mode 100644 index 00000000..aac3f538 --- /dev/null +++ b/docs/~/Queue.prototype.count.html @@ -0,0 +1,177 @@ + + + + Queue.prototype.count - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Queue.prototype.count +
+ + + + +
+
+ +

Get the number of items contained in the Queue

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ number + + + + + + +

number

+
+
+
+
+
+
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.dump.html b/docs/~/Queue.prototype.dump.html new file mode 100644 index 00000000..9d63fa3e --- /dev/null +++ b/docs/~/Queue.prototype.dump.html @@ -0,0 +1,177 @@ + + + + Queue.prototype.dump - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Queue.prototype.dump +
+ + + + +
+
+ +

Return all the items in the queue

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ QueueItem[] + + + + + + +

QueueItems[]

+
+
+
+
+
+
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.html b/docs/~/Queue.prototype.html new file mode 100644 index 00000000..730bda54 --- /dev/null +++ b/docs/~/Queue.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Queue.prototype.isEmpty.html b/docs/~/Queue.prototype.isEmpty.html new file mode 100644 index 00000000..9d7f13c1 --- /dev/null +++ b/docs/~/Queue.prototype.isEmpty.html @@ -0,0 +1,177 @@ + + + + Queue.prototype.isEmpty - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Queue.prototype.isEmpty +
+ + + + +
+
+ +

Check whether the Queue has any items

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ boolean + + + + + + +

boolean

+
+
+
+
+
+
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.items.html b/docs/~/Queue.prototype.items.html new file mode 100644 index 00000000..79438111 --- /dev/null +++ b/docs/~/Queue.prototype.items.html @@ -0,0 +1,156 @@ + + + + Queue.prototype.items - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.next.html b/docs/~/Queue.prototype.next.html new file mode 100644 index 00000000..543d679b --- /dev/null +++ b/docs/~/Queue.prototype.next.html @@ -0,0 +1,178 @@ + + + + Queue.prototype.next - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Queue.prototype.next +
+ + + + +
+
+ +

Get the next item from the queue. +Unlike the Queue#peek() method, this does remove the item.

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ QueueItem | null + + + + + + +

QueueItem

+
+
+
+
+
+
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.peek.html b/docs/~/Queue.prototype.peek.html new file mode 100644 index 00000000..78be8e2d --- /dev/null +++ b/docs/~/Queue.prototype.peek.html @@ -0,0 +1,178 @@ + + + + Queue.prototype.peek - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Queue.prototype.peek +
+ + + + +
+
+ +

Get the next item from the queue. +Unlike the Queue#next() method, this does not remove the item.

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ QueueItem | null + + + + + + +

QueueItem|null

+
+
+
+
+
+
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/Queue.prototype.scheduler.html b/docs/~/Queue.prototype.scheduler.html new file mode 100644 index 00000000..033afc90 --- /dev/null +++ b/docs/~/Queue.prototype.scheduler.html @@ -0,0 +1,156 @@ + + + + Queue.prototype.scheduler - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Queue } from ".";
+
+
+
+
+ + diff --git a/docs/~/RCON.html b/docs/~/RCON.html new file mode 100644 index 00000000..a7cdf0b9 --- /dev/null +++ b/docs/~/RCON.html @@ -0,0 +1,445 @@ + + + + RCON - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class RCON +
+ + + + +
+
+

+ + + + + + + + + + +Properties

+
+
+ + + + + + + + + + +
+ close(): Promise<void> + + + + + + +

Close connection to the server

+
+
+ + + + + + + + + + +
+ connect(ip: string, port: number, password?: string | null): Promise<void> + + + + + + +

Connect to an RCON server.

+
+
+ + + + + + + + + + +
+
private
+
recv(): Promise<string> + +
+ + + + +

Create a buffer to receive data from the server

+
+
+ + + + + + + + + + +
+ send(data: string, cmd?: keyof PacketType): Promise<string> + + + + + + +

Send data to the server

+
+
+ + + + + + + + + + +
+ sendSync(data: string, cmd?: keyof PacketType): void + + + + + + +

Send data to the server. +It is preferred to use RCON#send instead. +TODO: Return data received from server

+
+
+
+
+
+
+
+

Usage

import { RCON } from ".";
+
+
+
+
+ + diff --git a/docs/~/RCON.prototype.close.html b/docs/~/RCON.prototype.close.html new file mode 100644 index 00000000..a8db4acb --- /dev/null +++ b/docs/~/RCON.prototype.close.html @@ -0,0 +1,177 @@ + + + + RCON.prototype.close - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method RCON.prototype.close +
+ + + + +
+
+ +

Close connection to the server

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +

Promise

+
+
+
+
+
+
+
+
+

Usage

import { RCON } from ".";
+
+
+
+
+ + diff --git a/docs/~/RCON.prototype.conn.html b/docs/~/RCON.prototype.conn.html new file mode 100644 index 00000000..f79e45df --- /dev/null +++ b/docs/~/RCON.prototype.conn.html @@ -0,0 +1,156 @@ + + + + RCON.prototype.conn - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { RCON } from ".";
+
+
+
+
+ + diff --git a/docs/~/RCON.prototype.connect.html b/docs/~/RCON.prototype.connect.html new file mode 100644 index 00000000..50c2015b --- /dev/null +++ b/docs/~/RCON.prototype.connect.html @@ -0,0 +1,356 @@ + + + + RCON.prototype.connect - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method RCON.prototype.connect +
+ + + + +
+
+ +

Connect to an RCON server.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ ip: string + + + + + + +
+
+ + + + + + + + + + +
+ port: number + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
password: string | null = null + +
+ + + + +

Optional password for authentication

+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { RCON } from ".";
+
+
+
+
+ + diff --git a/docs/~/RCON.prototype.html b/docs/~/RCON.prototype.html new file mode 100644 index 00000000..093ec3c0 --- /dev/null +++ b/docs/~/RCON.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/RCON.prototype.recv.html b/docs/~/RCON.prototype.recv.html new file mode 100644 index 00000000..1fe99283 --- /dev/null +++ b/docs/~/RCON.prototype.recv.html @@ -0,0 +1,177 @@ + + + + RCON.prototype.recv - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method RCON.prototype.recv +
+ + + + +
+
+ +

Create a buffer to receive data from the server

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<string> + + + + + + +

Promise Data received from the server

+
+
+
+
+
+
+
+
+

Usage

import { RCON } from ".";
+
+
+
+
+ + diff --git a/docs/~/RCON.prototype.send.html b/docs/~/RCON.prototype.send.html new file mode 100644 index 00000000..6b160fd6 --- /dev/null +++ b/docs/~/RCON.prototype.send.html @@ -0,0 +1,305 @@ + + + + RCON.prototype.send - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method RCON.prototype.send +
+ + + + +
+
+ +

Send data to the server

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ data: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
cmd: keyof PacketType + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<string> + + + + + + +

Promise

+
+
+
+
+
+
+
+
+

Usage

import { RCON } from ".";
+
+
+
+
+ + diff --git a/docs/~/RCON.prototype.sendSync.html b/docs/~/RCON.prototype.sendSync.html new file mode 100644 index 00000000..142d90e2 --- /dev/null +++ b/docs/~/RCON.prototype.sendSync.html @@ -0,0 +1,307 @@ + + + + RCON.prototype.sendSync - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method RCON.prototype.sendSync +
+ + + + +
+
+ +

Send data to the server. +It is preferred to use RCON#send instead. +TODO: Return data received from server

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ data: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
cmd: keyof PacketType + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ void + + + + + + +

void

+
+
+
+
+
+
+
+
+

Usage

import { RCON } from ".";
+
+
+
+
+ + diff --git a/docs/~/Random.bytes.html b/docs/~/Random.bytes.html new file mode 100644 index 00000000..d079f7d1 --- /dev/null +++ b/docs/~/Random.bytes.html @@ -0,0 +1,323 @@ + + + + Random.bytes - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Random.bytes +
+ + + + +
+
+ +

Generate random bytes. +These bytes are generated using the Web Crypto API, this is cryptographically secure.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Random } from "https://deno.land/x/chomp/security/random.ts";
+
+// Generates 16 random bytes
+const bytes = Random.bytes(16);
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ length: number + + + + + + +

Amount of bytes to be generated

+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Uint8Array + + + + + + +

Uint8Array

+
+
+
+
+
+
+
+
+

Usage

import { Random } from ".";
+
+
+
+
+ + diff --git a/docs/~/Random.float.html b/docs/~/Random.float.html new file mode 100644 index 00000000..9249a59f --- /dev/null +++ b/docs/~/Random.float.html @@ -0,0 +1,474 @@ + + + + Random.float - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Random.float +
+ + + + +
+
+ +

Inclusively generate a random float between min and max. +If you do not want to use decimals, please use Random.integer() instead.

+

By default, these floats are NOT cryptographically secure (for performance reasons). +Set the "secure" argument to "true" if you are using this for cryptographic purposes!

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Random } from "https://deno.land/x/chomp/security/random.ts";
+
+// Generate a random float between 0 and 1
+const num = await Random.float(0, 1);
+
+
+
+
+
+ + + + + + + + + + +
+ +

Cryptographically secure

+
+
import { Random } from "https://deno.land/x/chomp/security/random.ts";
+
+// Generate a secure random float between 0 and 1
+const num = await Random.float(0, 1, true);
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+
optional
+
min: number = 0 + +
+ + + + +

Minimum allowable float

+
+
+ + + + + + + + + + +
+
optional
+
max: number = 1 + +
+ + + + +

Maximum allowable float

+
+
+ + + + + + + + + + +
+
optional
+
secure: boolean = false + +
+ + + + +

Using this for cryptographic purposes?

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Random } from ".";
+
+
+
+
+ + diff --git a/docs/~/Random.html b/docs/~/Random.html new file mode 100644 index 00000000..7c77c2bd --- /dev/null +++ b/docs/~/Random.html @@ -0,0 +1,321 @@ + + + + Random - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Random +
+ + + + +
+
+

+ + + + + + + + + + +Static Methods

+ + + + + + + + + + +
+ bytes(length: number): Uint8Array + + + + + + +

Generate random bytes. +These bytes are generated using the Web Crypto API, this is cryptographically secure.

+
+
+ + + + + + + + + + +
+ float(min?: number, max?: number, secure?: boolean): number + + + + + + +

Inclusively generate a random float between min and max. +If you do not want to use decimals, please use Random.integer() instead.

+

By default, these floats are NOT cryptographically secure (for performance reasons). +Set the "secure" argument to "true" if you are using this for cryptographic purposes!

+
+
+ + + + + + + + + + +
+ integer(min?: number, max?: number, secure?: boolean): number + + + + + + +

Inclusively generate a random integer between min and max. +If you want to use decimals, please use "Random.float() | Random.float()" instead.

+

By default, these integers are NOT cryptographically secure (for performance reasons). +Set the "secure" argument to "true" if you are using this for cryptographic purposes!

+
+
+ + + + + + + + + + +
+ string(length: number): Promise<string> + + + + + + +

Generate a random string. +These strings are generated using the Web Crypto API, this is cryptographically secure.

+
+
+
+
+
+
+
+

Usage

import { Random } from ".";
+
+
+
+
+ + diff --git a/docs/~/Random.integer.html b/docs/~/Random.integer.html new file mode 100644 index 00000000..41b3e687 --- /dev/null +++ b/docs/~/Random.integer.html @@ -0,0 +1,474 @@ + + + + Random.integer - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Random.integer +
+ + + + +
+
+ +

Inclusively generate a random integer between min and max. +If you want to use decimals, please use "Random.float() | Random.float()" instead.

+

By default, these integers are NOT cryptographically secure (for performance reasons). +Set the "secure" argument to "true" if you are using this for cryptographic purposes!

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Random } from "https://deno.land/x/chomp/security/random.ts";
+
+// Generate a random integer between 0 and 10
+const num = await Random.integer(0, 10);
+
+
+
+
+
+ + + + + + + + + + +
+ +

Cryptographically secure

+
+
import { Random } from "https://deno.land/x/chomp/security/random.ts";
+
+// Generate a secure random integer between 0 and 10
+const num = await Random.integer(0, 10, true);
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+
optional
+
min: number = 0 + +
+ + + + +

Minimum allowable integer

+
+
+ + + + + + + + + + +
+
optional
+
max: number = 1 + +
+ + + + +

Maximum allowable integer

+
+
+ + + + + + + + + + +
+
optional
+
secure: boolean = false + +
+ + + + +

Using this for cryptographic purposes?

+
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Random } from ".";
+
+
+
+
+ + diff --git a/docs/~/Random.prototype.html b/docs/~/Random.prototype.html new file mode 100644 index 00000000..808ab9b5 --- /dev/null +++ b/docs/~/Random.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Random.string.html b/docs/~/Random.string.html new file mode 100644 index 00000000..ccb44fbc --- /dev/null +++ b/docs/~/Random.string.html @@ -0,0 +1,323 @@ + + + + Random.string - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Random.string +
+ + + + +
+
+ +

Generate a random string. +These strings are generated using the Web Crypto API, this is cryptographically secure.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { Random } from "https://deno.land/x/chomp/security/random.ts";
+
+// Generates a string with 16 characters
+const str = await Random.string(16);
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ length: number + + + + + + +

Length of the string to be generated

+
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<string> + + + + + + +

Promise

+
+
+
+
+
+
+
+
+

Usage

import { Random } from ".";
+
+
+
+
+ + diff --git a/docs/~/Redis.connect.html b/docs/~/Redis.connect.html new file mode 100644 index 00000000..776ff13c --- /dev/null +++ b/docs/~/Redis.connect.html @@ -0,0 +1,306 @@ + + + + Redis.connect - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Redis.connect +
+ + + + +
+
+ +

Connect to a Redis node

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+
optional
+
hostname: string = 127.0.0.1 + +
+ + + + +
+
+ + + + + + + + + + +
+
optional
+
port: number = 6379 + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +

Promise

+
+
+
+
+
+
+
+
+

Usage

import { Redis } from ".";
+
+
+
+
+ + diff --git a/docs/~/Redis.connection.html b/docs/~/Redis.connection.html new file mode 100644 index 00000000..fa5b7956 --- /dev/null +++ b/docs/~/Redis.connection.html @@ -0,0 +1,156 @@ + + + + Redis.connection - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Redis } from ".";
+
+
+
+
+ + diff --git a/docs/~/Redis.getConnection.html b/docs/~/Redis.getConnection.html new file mode 100644 index 00000000..5c4b3d56 --- /dev/null +++ b/docs/~/Redis.getConnection.html @@ -0,0 +1,177 @@ + + + + Redis.getConnection - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Redis.getConnection +
+ + + + +
+
+ +

Return the redis connection

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ RedisConn + + + + + + +

any

+
+
+
+
+
+
+
+
+

Usage

import { Redis } from ".";
+
+
+
+
+ + diff --git a/docs/~/Redis.html b/docs/~/Redis.html new file mode 100644 index 00000000..b6c97342 --- /dev/null +++ b/docs/~/Redis.html @@ -0,0 +1,286 @@ + + + + Redis - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Redis } from ".";
+
+
+
+
+ + diff --git a/docs/~/Redis.prototype.html b/docs/~/Redis.prototype.html new file mode 100644 index 00000000..6ea83f53 --- /dev/null +++ b/docs/~/Redis.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Request.html b/docs/~/Request.html new file mode 100644 index 00000000..1c7c7b6c --- /dev/null +++ b/docs/~/Request.html @@ -0,0 +1,743 @@ + + + + Request - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Request +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
Request(
url: string
method: string
route: Route
headers: Headers
body: string
auth: string
ip?: string | null
)
+
+
+ + + + +
+
+
+
+
+
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getAuth.html b/docs/~/Request.prototype.getAuth.html new file mode 100644 index 00000000..03d75407 --- /dev/null +++ b/docs/~/Request.prototype.getAuth.html @@ -0,0 +1,175 @@ + + + + Request.prototype.getAuth - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getAuth +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getBody.html b/docs/~/Request.prototype.getBody.html new file mode 100644 index 00000000..4133c68c --- /dev/null +++ b/docs/~/Request.prototype.getBody.html @@ -0,0 +1,175 @@ + + + + Request.prototype.getBody - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getBody +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getHeaders.html b/docs/~/Request.prototype.getHeaders.html new file mode 100644 index 00000000..5f3cb106 --- /dev/null +++ b/docs/~/Request.prototype.getHeaders.html @@ -0,0 +1,175 @@ + + + + Request.prototype.getHeaders - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getHeaders +
+ + + + +
+
+ + +
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getIp.html b/docs/~/Request.prototype.getIp.html new file mode 100644 index 00000000..ca913265 --- /dev/null +++ b/docs/~/Request.prototype.getIp.html @@ -0,0 +1,175 @@ + + + + Request.prototype.getIp - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getIp +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ string | null + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getMethod.html b/docs/~/Request.prototype.getMethod.html new file mode 100644 index 00000000..aaed7656 --- /dev/null +++ b/docs/~/Request.prototype.getMethod.html @@ -0,0 +1,175 @@ + + + + Request.prototype.getMethod - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getMethod +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getParam.html b/docs/~/Request.prototype.getParam.html new file mode 100644 index 00000000..64612f01 --- /dev/null +++ b/docs/~/Request.prototype.getParam.html @@ -0,0 +1,251 @@ + + + + Request.prototype.getParam - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getParam +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ name: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ string | null + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getParams.html b/docs/~/Request.prototype.getParams.html new file mode 100644 index 00000000..cd712d84 --- /dev/null +++ b/docs/~/Request.prototype.getParams.html @@ -0,0 +1,175 @@ + + + + Request.prototype.getParams - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getParams +
+ + + + +
+
+ + +
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getQuery.html b/docs/~/Request.prototype.getQuery.html new file mode 100644 index 00000000..4b42a987 --- /dev/null +++ b/docs/~/Request.prototype.getQuery.html @@ -0,0 +1,251 @@ + + + + Request.prototype.getQuery - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getQuery +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ name: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ string | null + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getQueryParams.html b/docs/~/Request.prototype.getQueryParams.html new file mode 100644 index 00000000..60a06237 --- /dev/null +++ b/docs/~/Request.prototype.getQueryParams.html @@ -0,0 +1,175 @@ + + + + Request.prototype.getQueryParams - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getQueryParams +
+ + + + +
+
+ + +
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getRoute.html b/docs/~/Request.prototype.getRoute.html new file mode 100644 index 00000000..805a8e00 --- /dev/null +++ b/docs/~/Request.prototype.getRoute.html @@ -0,0 +1,175 @@ + + + + Request.prototype.getRoute - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getRoute +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.getUrl.html b/docs/~/Request.prototype.getUrl.html new file mode 100644 index 00000000..6dcb9419 --- /dev/null +++ b/docs/~/Request.prototype.getUrl.html @@ -0,0 +1,175 @@ + + + + Request.prototype.getUrl - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Request.prototype.getUrl +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Request } from ".";
+
+
+
+
+ + diff --git a/docs/~/Request.prototype.html b/docs/~/Request.prototype.html new file mode 100644 index 00000000..8508e9d0 --- /dev/null +++ b/docs/~/Request.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/RequestParameters.html b/docs/~/RequestParameters.html new file mode 100644 index 00000000..27ecad0c --- /dev/null +++ b/docs/~/RequestParameters.html @@ -0,0 +1,128 @@ + + + + RequestParameters - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { type RequestParameters } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router._controllerDir.html b/docs/~/Router._controllerDir.html new file mode 100644 index 00000000..c2b69707 --- /dev/null +++ b/docs/~/Router._controllerDir.html @@ -0,0 +1,156 @@ + + + + Router._controllerDir - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.add.html b/docs/~/Router.add.html new file mode 100644 index 00000000..6d7f72ac --- /dev/null +++ b/docs/~/Router.add.html @@ -0,0 +1,254 @@ + + + + Router.add - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Router.add +
+ + + + +
+
+ +

Add a route. +Defaults to 'GET'

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ route: Route + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ void + + + + + + +

void

+
+
+
+
+
+
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.execute.html b/docs/~/Router.execute.html new file mode 100644 index 00000000..4b50214f --- /dev/null +++ b/docs/~/Router.execute.html @@ -0,0 +1,304 @@ + + + + Router.execute - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Router.execute +
+ + + + +
+
+ +

Execute the requested controller action

+
+
+

+ + + + + + + + + + +Parameters

+
+ + + + + + + + + + +
+ clientIp: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<Response> + + + + + + +

Promise<Response|null>

+
+
+
+
+
+
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.getAuth.html b/docs/~/Router.getAuth.html new file mode 100644 index 00000000..2da8241a --- /dev/null +++ b/docs/~/Router.getAuth.html @@ -0,0 +1,253 @@ + + + + Router.getAuth - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Router.getAuth +
+ + + + +
+
+ +

Check if there is an authorization header set, return it if so

+
+
+

+ + + + + + + + + + +Parameters

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ string + + + + + + +

string

+
+
+
+
+
+
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.getBody.html b/docs/~/Router.getBody.html new file mode 100644 index 00000000..bf5a4d56 --- /dev/null +++ b/docs/~/Router.getBody.html @@ -0,0 +1,253 @@ + + + + Router.getBody - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Router.getBody +
+ + + + +
+
+ +

Get the body from the request

+
+
+

+ + + + + + + + + + +Parameters

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<string> + + + + + + +

Promise

+
+
+
+
+
+
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.getParams.html b/docs/~/Router.getParams.html new file mode 100644 index 00000000..a7520023 --- /dev/null +++ b/docs/~/Router.getParams.html @@ -0,0 +1,304 @@ + + + + Router.getParams - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Router.getParams +
+ + + + +
+
+ +

Get the parameters for the given route

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ route: ChompRoute + + + + + + +
+
+ + + + + + + + + + +
+ path: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +

RequestParameters

+
+
+
+
+
+
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.getQuery.html b/docs/~/Router.getQuery.html new file mode 100644 index 00000000..372e820e --- /dev/null +++ b/docs/~/Router.getQuery.html @@ -0,0 +1,253 @@ + + + + Router.getQuery - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Router.getQuery +
+ + + + +
+
+ +

Get the query parameters for the given route

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ path: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.getRoutes.html b/docs/~/Router.getRoutes.html new file mode 100644 index 00000000..4ddd8a99 --- /dev/null +++ b/docs/~/Router.getRoutes.html @@ -0,0 +1,124 @@ + + + + Router.getRoutes - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Router.getRoutes +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.html b/docs/~/Router.html new file mode 100644 index 00000000..3d9e963d --- /dev/null +++ b/docs/~/Router.html @@ -0,0 +1,651 @@ + + + + Router - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Router +
+ + + + +
+
+

+ + + + + + + + + + +Static Properties

+ + + + + + + + + + +
+
private
+
readonly
+
_controllerDir: string + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
routes: ChompRoute[] + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Static Methods

+ + + + + + + + + + +
+ add(route: Route): void + + + + + + +

Add a route. +Defaults to 'GET'

+
+
+ + + + + + + + + + +
+ execute(request: Request, clientIp: string): Promise<Response> + + + + + + +

Execute the requested controller action

+
+
+ + + + + + + + + + +
+ getAuth(request: Request): string + + + + + + +

Check if there is an authorization header set, return it if so

+
+
+ + + + + + + + + + +
+ getBody(request: Request): Promise<string> + + + + + + +

Get the body from the request

+
+
+ + + + + + + + + + +
+ getParams(route: ChompRoute, path: string): RequestParameters + + + + + + +

Get the parameters for the given route

+
+
+ + + + + + + + + + +
+ getQuery(path: string): QueryParameters + + + + + + +

Get the query parameters for the given route

+
+ +
+ + + + + + + + + + +
+ route(request: Request) + + + + + + +

Match the controller and action to a route

+
+
+
+
+
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.prototype.html b/docs/~/Router.prototype.html new file mode 100644 index 00000000..c08193bf --- /dev/null +++ b/docs/~/Router.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Router.route.html b/docs/~/Router.route.html new file mode 100644 index 00000000..f7677385 --- /dev/null +++ b/docs/~/Router.route.html @@ -0,0 +1,201 @@ + + + + Router.route - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Router.route +
+ + + + +
+
+ +

Match the controller and action to a route

+
+
+

+ + + + + + + + + + +Parameters

+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/Router.routes.html b/docs/~/Router.routes.html new file mode 100644 index 00000000..9a7a06ca --- /dev/null +++ b/docs/~/Router.routes.html @@ -0,0 +1,156 @@ + + + + Router.routes - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Router } from ".";
+
+
+
+
+ + diff --git a/docs/~/StatusCodes.html b/docs/~/StatusCodes.html new file mode 100644 index 00000000..2187c87b --- /dev/null +++ b/docs/~/StatusCodes.html @@ -0,0 +1,3318 @@ + + + + StatusCodes - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ enum StatusCodes +
+ + + + +
+
+ + + + + + + + + + +
+ ACCEPTED = 202 + + + + + + +
+
+ + + + + + + + + + +
+ ALREADY_REPORTED = 208 + + + + + + +
+
+ + + + + + + + + + +
+ BAD_GATEWAY = 502 + + + + + + +
+
+ + + + + + + + + + +
+ BAD_REQUEST = 400 + + + + + + +
+
+ + + + + + + + + + +
+ CONFLICT = 409 + + + + + + +
+
+ + + + + + + + + + +
+ CONTINUE = 100 + + + + + + +
+
+ + + + + + + + + + +
+ CREATED = 201 + + + + + + +
+
+ + + + + + + + + + +
+ EARLY_HINTS = 103 + + + + + + +
+
+ + + + + + + + + + +
+ EXPECTATION_FAILED = 417 + + + + + + +
+
+ + + + + + + + + + +
+ FAILED_DEPENDENCY = 424 + + + + + + +
+
+ + + + + + + + + + +
+ FORBIDDEN = 403 + + + + + + +
+
+ + + + + + + + + + +
+ FOUND = 302 + + + + + + +
+
+ + + + + + + + + + +
+ GATEWAY_TIMEOUT = 504 + + + + + + +
+
+ + + + + + + + + + +
+ GONE = 410 + + + + + + +
+
+ + + + + + + + + + +
+ HTTP_VERSION_NOT_SUPPORTED = 505 + + + + + + +
+
+ + + + + + + + + + +
+ IM_A_TEAPOT = 418 + + + + + + +
+
+ + + + + + + + + + +
+ IM_USED = 226 + + + + + + +
+
+ + + + + + + + + + +
+ INSUFFICIENT_STORAGE = 507 + + + + + + +
+
+ + + + + + + + + + +
+ INTERNAL_SERVER_ERROR = 500 + + + + + + +
+
+ + + + + + + + + + +
+ LENGTH_REQUIRED = 411 + + + + + + +
+
+ + + + + + + + + + +
+ LOCKED = 423 + + + + + + +
+
+ + + + + + + + + + +
+ LOOP_DETECTED = 508 + + + + + + +
+
+ + + + + + + + + + +
+ METHOD_NOT_ALLOWED = 405 + + + + + + +
+
+ + + + + + + + + + +
+ MISDIRECTED_REQUEST = 421 + + + + + + +
+
+ + + + + + + + + + +
+ MOVED_PERMANENTLY = 301 + + + + + + +
+
+ + + + + + + + + + +
+ MULTIPLE_CHOICES = 300 + + + + + + +
+
+ + + + + + + + + + +
+ MULTI_STATUS = 207 + + + + + + +
+
+ + + + + + + + + + +
+ NETWORK_AUTHENTICATION_REQUIRED = 511 + + + + + + +
+
+ + + + + + + + + + +
+ NON_AUTHORATIVE_INFORMATION = 203 + + + + + + +
+
+ + + + + + + + + + +
+ NOT_ACCEPTABLE = 406 + + + + + + +
+
+ + + + + + + + + + +
+ NOT_EXTENDED = 510 + + + + + + +
+
+ + + + + + + + + + +
+ NOT_FOUND = 404 + + + + + + +
+
+ + + + + + + + + + +
+ NOT_IMPLEMENTED = 501 + + + + + + +
+
+ + + + + + + + + + +
+ NOT_MODIFIED = 304 + + + + + + +
+
+ + + + + + + + + + +
+ NO_CONTENT = 204 + + + + + + +
+
+ + + + + + + + + + +
+ OK = 200 + + + + + + +
+
+ + + + + + + + + + +
+ PARTIAL_CONTENT = 206 + + + + + + +
+
+ + + + + + + + + + +
+ PAYLOAD_TOO_LARGE = 413 + + + + + + +
+
+ + + + + + + + + + +
+ PAYMENT_REQUIRED = 402 + + + + + + +
+
+ + + + + + + + + + +
+ PERMANENT_REDIRECT = 308 + + + + + + +
+
+ + + + + + + + + + +
+ PRECONDITION_FAILED = 412 + + + + + + +
+
+ + + + + + + + + + +
+ PRECONDITION_REQUIRED = 428 + + + + + + +
+
+ + + + + + + + + + +
+ PROCESSING = 102 + + + + + + +
+
+ + + + + + + + + + +
+ PROXY_AUTHENTICATION_REQUIRED = 407 + + + + + + +
+
+ + + + + + + + + + +
+ RANGE_NOT_SATISFIABLE = 416 + + + + + + +
+
+ + + + + + + + + + +
+ REQUEST_HEADER_FIELDS_TOO_LARGE = 431 + + + + + + +
+
+ + + + + + + + + + +
+ REQUEST_TIMEOUT = 408 + + + + + + +
+
+ + + + + + + + + + +
+ RESET_CONTENT = 205 + + + + + + +
+
+ + + + + + + + + + +
+ SEE_OTHER = 303 + + + + + + +
+
+ + + + + + + + + + +
+ SERVICE_UNAVAILABLE = 503 + + + + + + +
+
+ + + + + + + + + + +
+ SWITCHING_PROTOCOLS = 101 + + + + + + +
+
+ + + + + + + + + + +
+ TEMPORARY_REDIRECT = 307 + + + + + + +
+
+ + + + + + + + + + +
+ TOO_EARLY = 425 + + + + + + +
+
+ + + + + + + + + + +
+ TOO_MANY_REQUESTS = 429 + + + + + + +
+
+ + + + + + + + + + +
+ UNAUTHORIZED = 401 + + + + + + +
+ +
+ + + + + + + + + + +
+ UNPROCESSABLE_CONTENT = 422 + + + + + + +
+
+ + + + + + + + + + +
+ UNSUPPORTED_MEDIA_TYPE = 415 + + + + + + +
+
+ + + + + + + + + + +
+ UNUSED = 306 + + + + + + +
+
+ + + + + + + + + + +
+ UPGRADE_REQUIRED = 426 + + + + + + +
+
+ + + + + + + + + + +
+ URI_TOO_LONG = 414 + + + + + + +
+
+ + + + + + + + + + +
+ USE_PROXY = 305 + + + + + + +
+
+ + + + + + + + + + +
+ VARIANT_ALSO_NEGOTIATED = 506 + + + + + + +
+
+
+
+
+
+
+

Usage

import { StatusCodes } from ".";
+
+
+
+
+ + diff --git a/docs/~/Text.html b/docs/~/Text.html new file mode 100644 index 00000000..fa65b36c --- /dev/null +++ b/docs/~/Text.html @@ -0,0 +1,262 @@ + + + + Text - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Text } from ".";
+
+
+
+
+ + diff --git a/docs/~/Text.htmlentities.html b/docs/~/Text.htmlentities.html new file mode 100644 index 00000000..5681769f --- /dev/null +++ b/docs/~/Text.htmlentities.html @@ -0,0 +1,254 @@ + + + + Text.htmlentities - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Text.htmlentities +
+ + + + +
+
+ +

Replace special characters with their HTML entities. +TODO: Add support for diacritical marks.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ str: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ string + + + + + + +

string

+
+
+
+
+
+
+
+
+

Usage

import { Text } from ".";
+
+
+
+
+ + diff --git a/docs/~/Text.prototype.html b/docs/~/Text.prototype.html new file mode 100644 index 00000000..d8411d2f --- /dev/null +++ b/docs/~/Text.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Text.tokenize.html b/docs/~/Text.tokenize.html new file mode 100644 index 00000000..87980b82 --- /dev/null +++ b/docs/~/Text.tokenize.html @@ -0,0 +1,304 @@ + + + + Text.tokenize - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Text.tokenize +
+ + + + +
+
+ +

Tokenize a string into an array of strings.

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ input: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
limit: number = 3 + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ string[] + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Text } from ".";
+
+
+
+
+ + diff --git a/docs/~/Text.uuid.html b/docs/~/Text.uuid.html new file mode 100644 index 00000000..b515f916 --- /dev/null +++ b/docs/~/Text.uuid.html @@ -0,0 +1,176 @@ + + + + Text.uuid - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Text.uuid +
+ + + + +
+
+ +

Generate unique identifiers as per RFC-4122.

+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+
+

Usage

import { Text } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.html b/docs/~/Time.html new file mode 100644 index 00000000..4d614d9e --- /dev/null +++ b/docs/~/Time.html @@ -0,0 +1,983 @@ + + + + Time - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Time +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
Time(time?: string | undefined) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+ + + + + + + + +
+ + + + + + + + + + +
+
private
+
readonly
+
time + +
+ + + + +
+
+
+
+ + + + + + + + + + +
+ add(input: string) + + + + + + +
+
+ + + + + + + + + + +
+ addDay(days?: number) + + + + + + +
+
+ + + + + + + + + + +
+ addWeek(weeks?: number) + + + + + + +
+
+ + + + + + + + + + +
+ format(format: string) + + + + + + +
+ +
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.add.html b/docs/~/Time.prototype.add.html new file mode 100644 index 00000000..a6cc3a1b --- /dev/null +++ b/docs/~/Time.prototype.add.html @@ -0,0 +1,200 @@ + + + + Time.prototype.add - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.add +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ input: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.addDay.html b/docs/~/Time.prototype.addDay.html new file mode 100644 index 00000000..b6047f84 --- /dev/null +++ b/docs/~/Time.prototype.addDay.html @@ -0,0 +1,201 @@ + + + + Time.prototype.addDay - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.addDay +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+
optional
+
days: number = 1 + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.addWeek.html b/docs/~/Time.prototype.addWeek.html new file mode 100644 index 00000000..360b15bf --- /dev/null +++ b/docs/~/Time.prototype.addWeek.html @@ -0,0 +1,201 @@ + + + + Time.prototype.addWeek - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.addWeek +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+
optional
+
weeks: number = 1 + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.format.html b/docs/~/Time.prototype.format.html new file mode 100644 index 00000000..3a6a6a10 --- /dev/null +++ b/docs/~/Time.prototype.format.html @@ -0,0 +1,200 @@ + + + + Time.prototype.format - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.format +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ format: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.getTime.html b/docs/~/Time.prototype.getTime.html new file mode 100644 index 00000000..c70cda39 --- /dev/null +++ b/docs/~/Time.prototype.getTime.html @@ -0,0 +1,124 @@ + + + + Time.prototype.getTime - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.getTime +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.hours.html b/docs/~/Time.prototype.hours.html new file mode 100644 index 00000000..158a1edc --- /dev/null +++ b/docs/~/Time.prototype.hours.html @@ -0,0 +1,124 @@ + + + + Time.prototype.hours - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.hours +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.html b/docs/~/Time.prototype.html new file mode 100644 index 00000000..6878fb68 --- /dev/null +++ b/docs/~/Time.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Time.prototype.midnight.html b/docs/~/Time.prototype.midnight.html new file mode 100644 index 00000000..8ae5789e --- /dev/null +++ b/docs/~/Time.prototype.midnight.html @@ -0,0 +1,124 @@ + + + + Time.prototype.midnight - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.midnight +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.milliseconds.html b/docs/~/Time.prototype.milliseconds.html new file mode 100644 index 00000000..65c826c0 --- /dev/null +++ b/docs/~/Time.prototype.milliseconds.html @@ -0,0 +1,124 @@ + + + + Time.prototype.milliseconds - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.milliseconds +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.minutes.html b/docs/~/Time.prototype.minutes.html new file mode 100644 index 00000000..35bf58f5 --- /dev/null +++ b/docs/~/Time.prototype.minutes.html @@ -0,0 +1,124 @@ + + + + Time.prototype.minutes - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.minutes +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.month.html b/docs/~/Time.prototype.month.html new file mode 100644 index 00000000..3266de75 --- /dev/null +++ b/docs/~/Time.prototype.month.html @@ -0,0 +1,124 @@ + + + + Time.prototype.month - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.month +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.monthDay.html b/docs/~/Time.prototype.monthDay.html new file mode 100644 index 00000000..5786e116 --- /dev/null +++ b/docs/~/Time.prototype.monthDay.html @@ -0,0 +1,124 @@ + + + + Time.prototype.monthDay - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.monthDay +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.seconds.html b/docs/~/Time.prototype.seconds.html new file mode 100644 index 00000000..baddd57b --- /dev/null +++ b/docs/~/Time.prototype.seconds.html @@ -0,0 +1,124 @@ + + + + Time.prototype.seconds - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.seconds +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.time.html b/docs/~/Time.prototype.time.html new file mode 100644 index 00000000..754bfd10 --- /dev/null +++ b/docs/~/Time.prototype.time.html @@ -0,0 +1,79 @@ + + + + Time.prototype.time - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ property Time.prototype.time +
+ + + + +
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.weekDay.html b/docs/~/Time.prototype.weekDay.html new file mode 100644 index 00000000..df4634ed --- /dev/null +++ b/docs/~/Time.prototype.weekDay.html @@ -0,0 +1,124 @@ + + + + Time.prototype.weekDay - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.weekDay +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/Time.prototype.year.html b/docs/~/Time.prototype.year.html new file mode 100644 index 00000000..a370f7ae --- /dev/null +++ b/docs/~/Time.prototype.year.html @@ -0,0 +1,124 @@ + + + + Time.prototype.year - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Time.prototype.year +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Time } from ".";
+
+
+
+
+ + diff --git a/docs/~/TimeString.html b/docs/~/TimeString.html new file mode 100644 index 00000000..0a769f2e --- /dev/null +++ b/docs/~/TimeString.html @@ -0,0 +1,304 @@ + + + + TimeString - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ function TimeString +
+ + + + +
+
+ +

Takes a time string and turns it into milliseconds

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ strIn: TemplateStringsArray + + + + + + +
+
+ + + + + + + + + + +
+ ...parts: any[] + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ number + + + + + + +

number

+
+
+
+
+
+
+
+
+

Usage

import { TimeString } from ".";
+
+
+
+
+ + diff --git a/docs/~/TimeStringSeconds.html b/docs/~/TimeStringSeconds.html new file mode 100644 index 00000000..5cba3cb3 --- /dev/null +++ b/docs/~/TimeStringSeconds.html @@ -0,0 +1,304 @@ + + + + TimeStringSeconds - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ function TimeStringSeconds +
+ + + + +
+
+ +

Takes a time string and turns it into round seconds

+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ strIn: TemplateStringsArray + + + + + + +
+
+ + + + + + + + + + +
+ ...parts: any[] + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ number + + + + + + +

number

+
+
+
+
+
+
+
+
+

Usage

import { TimeStringSeconds } from ".";
+
+
+
+
+ + diff --git a/docs/~/ViewVariable.html b/docs/~/ViewVariable.html new file mode 100644 index 00000000..fbd1eef1 --- /dev/null +++ b/docs/~/ViewVariable.html @@ -0,0 +1,128 @@ + + + + ViewVariable - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { type ViewVariable } from ".";
+
+
+
+
+ + diff --git a/docs/~/Webserver.html b/docs/~/Webserver.html new file mode 100644 index 00000000..29efbae9 --- /dev/null +++ b/docs/~/Webserver.html @@ -0,0 +1,362 @@ + + + + Webserver - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Webserver } from ".";
+
+
+
+
+ + diff --git a/docs/~/Webserver.prototype.html b/docs/~/Webserver.prototype.html new file mode 100644 index 00000000..47cfedd7 --- /dev/null +++ b/docs/~/Webserver.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Webserver.prototype.serve.html b/docs/~/Webserver.prototype.serve.html new file mode 100644 index 00000000..6fe41a14 --- /dev/null +++ b/docs/~/Webserver.prototype.serve.html @@ -0,0 +1,251 @@ + + + + Webserver.prototype.serve - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Webserver.prototype.serve +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Webserver } from ".";
+
+
+
+
+ + diff --git a/docs/~/Webserver.prototype.server.html b/docs/~/Webserver.prototype.server.html new file mode 100644 index 00000000..d72c9ca2 --- /dev/null +++ b/docs/~/Webserver.prototype.server.html @@ -0,0 +1,156 @@ + + + + Webserver.prototype.server - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Webserver } from ".";
+
+
+
+
+ + diff --git a/docs/~/Webserver.prototype.start.html b/docs/~/Webserver.prototype.start.html new file mode 100644 index 00000000..408a9ea1 --- /dev/null +++ b/docs/~/Webserver.prototype.start.html @@ -0,0 +1,175 @@ + + + + Webserver.prototype.start - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Webserver.prototype.start +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Webserver } from ".";
+
+
+
+
+ + diff --git a/docs/~/Websocket.html b/docs/~/Websocket.html new file mode 100644 index 00000000..0c7f72d0 --- /dev/null +++ b/docs/~/Websocket.html @@ -0,0 +1,571 @@ + + + + Websocket - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ class Websocket +
+ + + + +
+
+

+ + + + + + + + + + +Constructors

+ + + + + + + + + + +
+
new
+
Websocket(port?: number, authenticate?: boolean) + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Properties

+ + + + + + + + + + +
+
private
+
readonly
+
authenticate: boolean + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
readonly
+
port: number + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
server: WebSocketServer | null + +
+ + + + +
+
+
+
+ + + + + + + + + + +
+ broadcast(eventString: string, data: any): void + + + + + + +
+
+ + + + + + + + + + +
+
private
+
handleEvent(event: string, data?: any) + +
+ + + + +
+
+ + + + + + + + + + +
+
private
+
onMessage(message: string): Promise<void> + +
+ + + + +
+ +
+
+
+
+
+
+

Usage

import { Websocket } from ".";
+
+
+
+
+ + diff --git a/docs/~/Websocket.prototype.authenticate.html b/docs/~/Websocket.prototype.authenticate.html new file mode 100644 index 00000000..60076667 --- /dev/null +++ b/docs/~/Websocket.prototype.authenticate.html @@ -0,0 +1,156 @@ + + + + Websocket.prototype.authenticate - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Websocket } from ".";
+
+
+
+
+ + diff --git a/docs/~/Websocket.prototype.broadcast.html b/docs/~/Websocket.prototype.broadcast.html new file mode 100644 index 00000000..1a8fecab --- /dev/null +++ b/docs/~/Websocket.prototype.broadcast.html @@ -0,0 +1,302 @@ + + + + Websocket.prototype.broadcast - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Websocket.prototype.broadcast +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ eventString: string + + + + + + +
+
+ + + + + + + + + + +
+ data: any + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Websocket } from ".";
+
+
+
+
+ + diff --git a/docs/~/Websocket.prototype.handleEvent.html b/docs/~/Websocket.prototype.handleEvent.html new file mode 100644 index 00000000..c7f446e9 --- /dev/null +++ b/docs/~/Websocket.prototype.handleEvent.html @@ -0,0 +1,252 @@ + + + + Websocket.prototype.handleEvent - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Websocket.prototype.handleEvent +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ event: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
data: any = [UNSUPPORTED] + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Websocket } from ".";
+
+
+
+
+ + diff --git a/docs/~/Websocket.prototype.html b/docs/~/Websocket.prototype.html new file mode 100644 index 00000000..9051e529 --- /dev/null +++ b/docs/~/Websocket.prototype.html @@ -0,0 +1 @@ + diff --git a/docs/~/Websocket.prototype.onMessage.html b/docs/~/Websocket.prototype.onMessage.html new file mode 100644 index 00000000..24d59ca0 --- /dev/null +++ b/docs/~/Websocket.prototype.onMessage.html @@ -0,0 +1,251 @@ + + + + Websocket.prototype.onMessage - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Websocket.prototype.onMessage +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ message: string + + + + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+ + + + + + + + + + +
+ Promise<void> + + + + + + +
+
+
+
+
+
+
+
+

Usage

import { Websocket } from ".";
+
+
+
+
+ + diff --git a/docs/~/Websocket.prototype.port.html b/docs/~/Websocket.prototype.port.html new file mode 100644 index 00000000..9506096b --- /dev/null +++ b/docs/~/Websocket.prototype.port.html @@ -0,0 +1,156 @@ + + + + Websocket.prototype.port - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Websocket } from ".";
+
+
+
+
+ + diff --git a/docs/~/Websocket.prototype.server.html b/docs/~/Websocket.prototype.server.html new file mode 100644 index 00000000..c2cc2705 --- /dev/null +++ b/docs/~/Websocket.prototype.server.html @@ -0,0 +1,156 @@ + + + + Websocket.prototype.server - Chomp documentation + + + + + + + + + + + + + +
+
+
+

Usage

import { Websocket } from ".";
+
+
+
+
+ + diff --git a/docs/~/Websocket.prototype.start.html b/docs/~/Websocket.prototype.start.html new file mode 100644 index 00000000..ab6f8d43 --- /dev/null +++ b/docs/~/Websocket.prototype.start.html @@ -0,0 +1,175 @@ + + + + Websocket.prototype.start - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ method Websocket.prototype.start +
+ + + + +
+
+ +
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { Websocket } from ".";
+
+
+
+
+ + diff --git a/docs/~/raise.html b/docs/~/raise.html new file mode 100644 index 00000000..ae10aee3 --- /dev/null +++ b/docs/~/raise.html @@ -0,0 +1,547 @@ + + + + raise - Chomp documentation + + + + + + + + + + + + + +
+
+
+
+ function raise +
+ + + + +
+
+ +

Utility function that throws an error. +Band-aid for JS not supporting throwing in null-coalescing.

+
+
+ + + + + + + + + + +
+ +

Basic Usage

+
+
import { raise } from "https://deno.land/x/chomp/error/raise.ts";
+
+const myVar = null ?? raise('Error Message');
+
+
+
+
+
+ + + + + + + + + + +
+ +

Custom Error types

+
+
import { raise } from "https://deno.land/x/chomp/error/raise.ts";
+
+const myVar = null ?? raise('Error Message', 'CustomError');
+
+// Will automatically append "Error" to the name
+const myVar = null ?? raise('Error Message', 'Custom');
+
+
+
+
+
+ + + + + + + + + + +
+ +

Custom Error (using Error-classes)

+
+
import { raise } from "https://deno.land/x/chomp/error/raise.ts";
+
+class CustomError extends Error {
+  constructor(public message: string) {
+    super(message);
+  }
+}
+
+const myVar = null ?? raise('Error Message', CustomError);
+
+
+
+
+
+
+
+

+ + + + + + + + + + +Type Parameters

+ + + + + + + + + + +
+ CustomError extends Error + + + + + + +
+
+
+
+

+ + + + + + + + + + +Parameters

+ + + + + + + + + + +
+ err: string + + + + + + +
+
+ + + + + + + + + + +
+
optional
+
type: string | (new (err: string) => CustomError) | "Error" = Error + +
+ + + + +
+
+
+
+

+ + + + + + + + + + +Return Type

+
+
+
+
+
+
+

Usage

import { raise } from ".";
+
+
+
+
+ + diff --git a/error/raise.ts b/error/raise.ts index 584329c5..7893df0c 100644 --- a/error/raise.ts +++ b/error/raise.ts @@ -1,11 +1,41 @@ /** * Utility function that throws an error. * Band-aid for JS not supporting throwing in null-coalescing. - * + * + * @example Basic Usage + * ```ts + * import { raise } from "https://deno.land/x/chomp/error/raise.ts"; + * + * const myVar = null ?? raise('Error Message'); + * ``` + * + * @example Custom Error types + * ```ts + * import { raise } from "https://deno.land/x/chomp/error/raise.ts"; + * + * const myVar = null ?? raise('Error Message', 'CustomError'); + * + * // Will automatically append "Error" to the name + * const myVar = null ?? raise('Error Message', 'Custom'); + * ``` + * + * @example Custom Error (using Error-classes) + * ```ts + * import { raise } from "https://deno.land/x/chomp/error/raise.ts"; + * + * class CustomError extends Error { + * constructor(public message: string) { + * super(message); + * } + * } + * + * const myVar = null ?? raise('Error Message', CustomError); + * ``` + * * @param err * @param type */ -export function raise(err: string, type: string|(new (err: string) => CustomError)|'Error' = 'Error'){ +export function raise(err: string, type: string|(new (err: string) => CustomError)|'Error' = 'Error'): never { // Check if we want to throw a specific class if(typeof type === 'function' && type.prototype instanceof Error) { const e = new type(err); @@ -13,15 +43,15 @@ export function raise(err: string, type: string|(new e.name = type.name; throw e; } - + // Initialize regular error // Then add our stacktrace const e = new Error(err); Error.captureStackTrace(e, raise); - + // Check if we want to change the name if(type !== "Error") e.name = (type as string).slice(-5).toLowerCase() !== "error" ? `${type}Error`: type as string; - + // Throw the error throw e; } diff --git a/filesystem/folder.ts b/filesystem/folder.ts index 65c0865c..8f9eb5dd 100644 --- a/filesystem/folder.ts +++ b/filesystem/folder.ts @@ -21,7 +21,7 @@ export class Folder { /** * Create the directory if it does not exist yet. - * + * * @param options Options with which to create the directory */ public async create(options?: Deno.MkdirOptions): Promise { diff --git a/mod.ts b/mod.ts index ce462bb9..1982c260 100644 --- a/mod.ts +++ b/mod.ts @@ -1,10 +1,65 @@ /** - * These are just the exports you'll most commonly use. - * You can view the "docs"-directory to see what else there is! + * Communication + */ +export { CouchDB } from "./communication/couchdb.ts"; +export { Druid } from "./communication/druid.ts"; +export { GraphQL } from "./communication/graphql.ts"; +export { InfluxDB } from "./communication/influxdb.ts" +export { Loki } from "./communication/loki.ts"; +export { Ntfy } from "./communication/ntfy.ts"; +export { Nut } from "./communication/nut.ts"; +export { RCON } from "./communication/rcon.ts"; +export { Redis } from "./communication/redis.ts"; + +/** + * Chomp Core + */ +export * from "./core/mod.ts"; + +/** + * Error + */ +export type { ErrorCodes } from "./error/error-codes.ts"; +export { raise } from "./error/raise.ts"; + +/** + * Filesystem */ -export { Cache } from "./core/cache.ts"; -export { Configure } from "./core/configure.ts"; -export { Logger } from "./core/logger.ts"; export { File } from "./filesystem/file.ts"; export { Folder } from "./filesystem/folder.ts"; + +/** + * Queue + */ +export { Queue } from "./queue/queue.ts"; + +/** + * Security + */ +export { Hash } from "./security/hash.ts"; +export { Password } from "./security/password.ts"; +export { Random } from "./security/random.ts"; +export type { Algorithms, INSECURE_ALGORITHMS } from "./security/hash.ts"; +export type { PASSWORD_DEFAULT, DEFAULT_OPTS, PasswordOptions } from "./security/password.ts"; + +/** + * Utility + */ export { CheckSource } from "./utility/check-source.ts"; +export { Cron } from "./utility/cron.ts"; +export { empty } from "./utility/empty.ts"; +export { Inflector} from "./utility/inflector.ts"; +export { Text } from "./utility/text.ts"; +export { Time } from "./utility/time.ts"; +export { TimeString, TimeStringSeconds } from "./utility/time-string.ts"; +export type { ExclusionConfig } from "./utility/check-source.ts"; + +/** + * Webserver + */ +export * from "./webserver/mod.ts"; + +/** + * Websocket + */ +export * from "./websocket/mod.ts"; diff --git a/security/hash.ts b/security/hash.ts index cc676d44..ed3633e7 100644 --- a/security/hash.ts +++ b/security/hash.ts @@ -55,10 +55,42 @@ export class Hash { private algo: string, ) {} + /** + * Digest the input + * + * @example Basic usage + * ```ts + * import { Hash } from "https://deno.land/x/chomp/security/hash.ts"; + * + * const hash = new Hash("some data"); + * await hash.digest(); + * console.log(hash.hex()); + * ``` + * + * @example Using BLAKE2B384 + * ```ts + * import { Hash, Algorithms } from "https://deno.land/x/chomp/security/hash.ts"; + * + * const hash = new Hash("some data", Algorithms.BLAKE2B384); + * await hash.digest(); + * ``` + */ public async digest() { this.result = await crypto.subtle.digest(this.algo as DigestAlgorithm, new TextEncoder().encode(this.input)); } + /** + * Digest the input + * + * @example Basic usage + * ```ts + * import { Hash } from "https://deno.land/x/chomp/security/hash.ts"; + * + * const hash = new Hash("some data"); + * await hash.digest(); + * console.log(hash.hex()); + * ``` + */ public hex() { return [...new Uint8Array(this.result)].map(x => x.toString(16).padStart(2, '0')).join(''); } diff --git a/security/password.ts b/security/password.ts index 1f862d8a..30becf08 100644 --- a/security/password.ts +++ b/security/password.ts @@ -45,8 +45,11 @@ enum HASH_IDENTIFIERS { 'db7' = 'MD5', } -// Set default options for hashing -export const DEFAULT_OPTS: IPasswordOpts = { +/** + * Default options for password hashing. + * These defaults offer a good balance between performance and security. + */ +export const DEFAULT_OPTS: PasswordOptions = { cost: 10, allowInsecure: false } @@ -54,7 +57,7 @@ export const DEFAULT_OPTS: IPasswordOpts = { /** * Options for hashing a password */ -export interface IPasswordOpts { +export interface PasswordOptions { /* Cost factor for hashing (2**cost) */ cost?: number; /* Allow the use of insecure algorithms */ @@ -68,9 +71,9 @@ export class Password { * @param password * @param algo * @param options - * @returns Promise Hash string containing algo, cost, salt and hash + * @returns Hash string containing algo, cost, salt and hash */ - public static async hash(password: string, algo: Algorithms = PASSWORD_DEFAULT, options: IPasswordOpts = DEFAULT_OPTS): Promise { + public static async hash(password: string, algo: Algorithms = PASSWORD_DEFAULT, options: PasswordOptions = DEFAULT_OPTS): Promise { // Make sure we are not using an insecure algorithm if(INSECURE_ALGORITHMS.includes(algo) && !options.allowInsecure) throw Error('Insecure hashing algorithm selected, aborting.'); diff --git a/utility/check-source.ts b/utility/check-source.ts index 2bea890a..eb6d1b3e 100644 --- a/utility/check-source.ts +++ b/utility/check-source.ts @@ -6,6 +6,35 @@ export interface ExclusionConfig { files?: string[]; } +/** + * Check all files in the specified directories. + * Doing this allows the program to start up significantly faster after deployment. + * It is **NOT** a replacement for "deno lint". + * + * @example Basic Usage + * ```ts + * import { CheckSource } from "https://deno.land/x/chomp/utility/check-source.ts"; + * + * const checker = new CheckSource(['./src']); + * await checker.run(); + * ``` + * + * @example Exclude a directory + * ```ts + * import { CheckSource } from "https://deno.land/x/chomp/utility/check-source.ts"; + * + * const checker = new CheckSource(['./src'], { directories: 'my-directory' }); + * await checker.run(); + * ``` + * + * @example Exclude a file + * ```ts + * import { CheckSource } from "https://deno.land/x/chomp/utility/check-source.ts"; + * + * const checker = new CheckSource(['./src'], { files: './src/my-directory/my-file.txt' }); + * await checker.run(); + * ``` + */ export class CheckSource { private files: string[] = []; private errors = 0; diff --git a/utility/time-string.ts b/utility/time-string.ts index fbc78b33..9133157e 100644 --- a/utility/time-string.ts +++ b/utility/time-string.ts @@ -74,7 +74,7 @@ function parseNumberFormat(digit: string, unit: string): number { * @returns number */ // deno-lint-ignore no-explicit-any -- TODO -export function T(strIn: TemplateStringsArray, ...parts: any[]): number { +export function TimeString(strIn: TemplateStringsArray, ...parts: any[]): number { const str = String.raw(strIn, parts).toLowerCase().replace(/\s/g, ''); const parsed = [...str.matchAll(TimeRegexp)]; if (parsed.length === 0) @@ -88,12 +88,12 @@ export function T(strIn: TemplateStringsArray, ...parts: any[]): number { /** * Takes a time string and turns it into round seconds - * + * * @param strIn * @param parts * @returns number */ // deno-lint-ignore no-explicit-any -- TODO -export function _T(strIn: TemplateStringsArray, ...parts: any[]): number { +export function TimeStringSeconds(strIn: TemplateStringsArray, ...parts: any[]): number { return Math.round(T(strIn, parts) / 1000); } diff --git a/utility/time.ts b/utility/time.ts index 0bdc1eaa..3052ac70 100644 --- a/utility/time.ts +++ b/utility/time.ts @@ -1,6 +1,6 @@ import { time as timets } from "https://denopkg.com/burhanahmeed/time.ts@v2.0.1/mod.ts"; import { format as formatter } from "https://cdn.deno.land/std/versions/0.77.0/raw/datetime/mod.ts"; -import { T } from "./time-string.ts"; +import { TimeString } from "./time-string.ts"; export class Time { private readonly time; @@ -28,7 +28,7 @@ export class Time { } public add(input: string) { - this.time.setMilliseconds(this.time.getMilliseconds() + T`${input}`); + this.time.setMilliseconds(this.time.getMilliseconds() + TimeString`${input}`); return this; } diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index b203104b..a87d3166 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -20,7 +20,7 @@ export class Controller { /** * Set the 'Content-Type' header - * + * * @deprecated Please use "Controller.getResponse().withType()" instead. * @param value */ @@ -37,11 +37,11 @@ export class Controller { /** * Initialize the controller. * Literally does nothing at this moment except exist to prevent errors. - * + * * @protected */ public async initialize(): Promise {} - + /** * Get the request object for this controller * @@ -50,10 +50,10 @@ export class Controller { protected getRequest(): Request { return this.request; } - + /** * Get the response object for this controller - * + * * @protected */ protected getResponse(): ResponseBuilder { @@ -68,7 +68,7 @@ export class Controller { this[Inflector.ucfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); return this; } - + // Import the module const module = await import(`${Controller._componentDir}/${Inflector.lcfirst(name)}.ts`); @@ -81,16 +81,16 @@ export class Controller { if(!(module[`${Inflector.ucfirst(name)}Component`].prototype instanceof Component)) { raise(`Class "${Inflector.ucfirst(name)}Component" does not properly extend Chomp's component.`); } - + // Add the component to the registry Registry.add(`${Inflector.ucfirst(name)}Component`, module); - + // Add the module as class property this[Inflector.ucfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); - + return this; } - + /** * Set a view variable * @@ -128,7 +128,7 @@ export class Controller { break; } } - + // Check if we can compress with Brotli // TODO: Hope that Deno will make this obsolete. if(this.getRequest().getHeaders().get('accept-encoding')?.includes('br') && canCompress && body.length > 1024) { @@ -137,7 +137,7 @@ export class Controller { Logger.debug(`Compressed body with brotli: ${body.length}-bytes`); this.getResponse().withHeader('Content-Encoding', 'br'); } - + // Set our final body this.getResponse().withBody(body); } diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index b87c81f7..c5d6112e 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -76,7 +76,7 @@ export class Router { } ); } - + // Build our Request object const req = new ChompRequest( request.url, @@ -95,17 +95,17 @@ export class Router { try { // Import the module const module = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.getRoute().getController())}.controller.ts`); - + // Make sure the controller class was found if(!(`${req.getRoute().getController()}Controller` in module)) { raise(`No class "${req.getRoute().getController()}Controller" could be found.`); } - + // Make sure the controller class extends our base controller if(!(module[`${req.getRoute().getController()}Controller`].prototype instanceof Controller)) { raise(`Class "${req.getRoute().getController()}Controller" does not properly extend Chomp's controller.`); } - + // Add the module to our registry Registry.add(`${req.getRoute().getController()}Controller`, module); } catch(e) { @@ -121,7 +121,7 @@ export class Router { ); } } - + // Run our controller try { // Instantiate the controller @@ -130,7 +130,7 @@ export class Router { // Run the controller's initializer await controller.initialize(); - + // Execute our action await controller[req.getRoute().getAction()](); @@ -164,7 +164,7 @@ export class Router { // Strip off query parameters const pathSplit = path.split("%3F"); path = pathSplit[0]; - + const keys: string[] = []; const r = pathToRegexp(route.getPath(), keys).exec(path) || []; @@ -173,7 +173,7 @@ export class Router { /** * Get the query parameters for the given route - * + * * @param path * @returns QueryParameters */ @@ -181,7 +181,7 @@ export class Router { const params = new URLSearchParams(path.split("?")[1]); return Object.fromEntries(params.entries()); } - + /** * Get the body from the request * diff --git a/webserver/webserver.ts b/webserver/webserver.ts index d9461db7..f163671e 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -32,7 +32,7 @@ export class Webserver { try { // Run the required route const response: Response = await Router.execute(request.request, (conn.remoteAddr as Deno.NetAddr).hostname!); - + // Send our response await request.respondWith(response); } catch(e) { diff --git a/websocket/websocket.ts b/websocket/websocket.ts index e55fa421..8f12cd5c 100644 --- a/websocket/websocket.ts +++ b/websocket/websocket.ts @@ -57,7 +57,7 @@ export class Websocket { // Decode the message const data = JSON.parse(message); - + // Get the Event let event = data.event; const tokens = []; From 1515931b6382206384186542d8b0ac21d48a7758 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 17:12:12 +0200 Subject: [PATCH 218/379] Fix some imports --- core/cache.ts | 4 ++-- core/configure.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index 8bd5baac..aebb0b7a 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -1,5 +1,5 @@ -import { T as TimeString } from "../utility/time-string.ts"; -import { Logger } from "../core/logger.ts"; +import { TimeString } from "../utility/time-string.ts"; +import { Logger } from "./logger.ts"; import { Cron } from "../utility/cron.ts"; interface CacheItem { diff --git a/core/configure.ts b/core/configure.ts index b489097c..4e687638 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,4 +1,4 @@ -import { Logger } from "../core/logger.ts"; +import { Logger } from "./logger.ts"; // deno-lint-ignore no-explicit-any -- Arbitrary data may be used const defaults = new Map([ From 04d920d289b0645bcd1cdd8b7fe3915df33b4df4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 17:12:17 +0200 Subject: [PATCH 219/379] Fix tests --- tests/discord/utility.test.ts | 9 --------- utility/time-string.ts | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 10 deletions(-) delete mode 100644 tests/discord/utility.test.ts diff --git a/tests/discord/utility.test.ts b/tests/discord/utility.test.ts deleted file mode 100644 index bab0ba27..00000000 --- a/tests/discord/utility.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { snowflakeToDate } from "../../discord/util/snowflake-to-date.ts"; - -Deno.test("Discord Utilities Test", async (t) => { - await t.step("snowflakeToDate", () => { - assertEquals(snowflakeToDate(91616138860978176n), new Date('2015-09-10T19:29:49.650Z')); - assertEquals(snowflakeToDate(1011419238923255838n),new Date('2022-08-22T23:38:57.820Z')); - }); -}); diff --git a/utility/time-string.ts b/utility/time-string.ts index 9133157e..e2f11d78 100644 --- a/utility/time-string.ts +++ b/utility/time-string.ts @@ -69,6 +69,13 @@ function parseNumberFormat(digit: string, unit: string): number { /** * Takes a time string and turns it into milliseconds * + * @example + * ```ts + * import { TimeStringSeconds } from "https://deno.land/x/chomp/utility/time-string.ts"; + * + * const milliseconds = TimeString`+1 minute`; + * ``` + * * @param strIn * @param parts * @returns number @@ -89,11 +96,18 @@ export function TimeString(strIn: TemplateStringsArray, ...parts: any[]): number /** * Takes a time string and turns it into round seconds * + * @example + * ```ts + * import { TimeStringSeconds } from "https://deno.land/x/chomp/utility/time-string.ts"; + * + * const seconds = TimeStringSeconds`+1 minute`; + * ``` + * * @param strIn * @param parts * @returns number */ // deno-lint-ignore no-explicit-any -- TODO export function TimeStringSeconds(strIn: TemplateStringsArray, ...parts: any[]): number { - return Math.round(T(strIn, parts) / 1000); + return Math.round(TimeString(strIn, parts) / 1000); } From 70fad8a9ed26b399f63dfa89dba7abf72441a338 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 17:13:40 +0200 Subject: [PATCH 220/379] Update docs --- deno.lock | 4 ++ docs/search_index.js | 2 +- docs/~/Controller.html | 12 +++--- docs/~/Queue.html | 4 +- docs/~/Time.html | 4 +- docs/~/TimeString.html | 70 ++++++++++++++++++++++++++++++++++- docs/~/TimeStringSeconds.html | 70 ++++++++++++++++++++++++++++++++++- docs/~/Websocket.html | 8 ++-- 8 files changed, 155 insertions(+), 19 deletions(-) diff --git a/deno.lock b/deno.lock index fc7368e9..a187316c 100644 --- a/deno.lock +++ b/deno.lock @@ -5,6 +5,10 @@ "https://cdn.deno.land/std/versions/0.77.0/raw/datetime/mod.ts": "5d31444e61524f399ac17aa75401b7e47a7b2f6ccaa36575416a1253a8f61afa", "https://cdn.deno.land/std/versions/0.77.0/raw/datetime/tokenizer.ts": "ae21a459f2f017ac81b1b49caa81174b6b8ab8a4d8d82195dcf25bb67b565c71", "https://deno.land/std@0.117.0/fmt/colors.ts": "8368ddf2d48dfe413ffd04cdbb7ae6a1009cf0dccc9c7ff1d76259d9c61a0621", + "https://deno.land/std@0.152.0/fmt/colors.ts": "6f9340b7fb8cc25a993a99e5efc56fe81bb5af284ff412129dd06df06f53c0b4", + "https://deno.land/std@0.152.0/testing/_diff.ts": "029a00560b0d534bc0046f1bce4bd36b3b41ada3f2a3178c85686eb2ff5f1413", + "https://deno.land/std@0.152.0/testing/_format.ts": "0d8dc79eab15b67cdc532826213bbe05bccfd276ca473a50a3fc7bbfb7260642", + "https://deno.land/std@0.152.0/testing/asserts.ts": "093735c88f52bbead7f60a1f7a97a2ce4df3c2d5fab00a46956f20b4a5793ccd", "https://deno.land/x/croner@5.3.4/src/croner.js": "a7e06cd5c262c60bc9736d735eb65ae2e401eed3d965c467087a5a575abd8ec2", "https://deno.land/x/croner@5.3.4/src/date.js": "e5bfdf17750207a00e1399c50bda7be8746429619c9f2fc0679c678aed22febc", "https://deno.land/x/croner@5.3.4/src/helpers/minitz.js": "8b3824fadd0130b4faf38335a064febdf77c5582dcaa06f443b901e9b8233130", diff --git a/docs/search_index.js b/docs/search_index.js index fe6ce6ac..87e79a01 100644 --- a/docs/search_index.js +++ b/docs/search_index.js @@ -1,3 +1,3 @@ (function () { - window.DENO_DOC_SEARCH_INDEX = {"nodes":[{"kind":["enum"],"name":"Algorithms","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":229},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Authenticator","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":95},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Cache","file":".","location":{"filename":"","line":10,"col":0,"byteIndex":222},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"CheckSource","file":".","location":{"filename":"","line":38,"col":0,"byteIndex":1093},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Configure","file":".","location":{"filename":"","line":9,"col":0,"byteIndex":233},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Controller","file":".","location":{"filename":"","line":15,"col":0,"byteIndex":574},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"CouchDB","file":".","location":{"filename":"","line":21,"col":0,"byteIndex":355},"declarationKind":"export","deprecated":false},{"kind":["function","namespace"],"name":"Cron","file":".","location":{"filename":"","line":56,"col":0,"byteIndex":2427},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"Cron.Cron","file":".","location":{"filename":"","line":325,"col":5,"byteIndex":9058},"declarationKind":"declare","deprecated":false},{"kind":["variable"],"name":"DEFAULT_OPTS","file":".","location":{"filename":"","line":52,"col":13,"byteIndex":1435},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Druid","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["enum"],"name":"ErrorCodes","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Events","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":102},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"ExclusionConfig","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":94},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"File","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Folder","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":47},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"GraphQL","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Hash","file":".","location":{"filename":"","line":50,"col":0,"byteIndex":1339},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"INSECURE_ALGORITHMS","file":".","location":{"filename":"","line":41,"col":13,"byteIndex":1177},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Inflector","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":63},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"InfluxDB","file":".","location":{"filename":"","line":16,"col":0,"byteIndex":184},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Logger","file":".","location":{"filename":"","line":44,"col":0,"byteIndex":1500},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Loki","file":".","location":{"filename":"","line":9,"col":0,"byteIndex":179},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Ntfy","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":48},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Nut","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":152},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"PASSWORD_DEFAULT","file":".","location":{"filename":"","line":8,"col":13,"byteIndex":247},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Password","file":".","location":{"filename":"","line":67,"col":0,"byteIndex":1718},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"PasswordOptions","file":".","location":{"filename":"","line":60,"col":0,"byteIndex":1549},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"QueryParameters","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":118},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Queue","file":".","location":{"filename":"","line":20,"col":0,"byteIndex":333},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"RCON","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":132},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Random","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Redis","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":148},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Request","file":".","location":{"filename":"","line":11,"col":0,"byteIndex":186},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"RequestParameters","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":48},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Router","file":".","location":{"filename":"","line":20,"col":0,"byteIndex":762},"declarationKind":"export","deprecated":false},{"kind":["enum"],"name":"StatusCodes","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Text","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Time","file":".","location":{"filename":"","line":5,"col":0,"byteIndex":242},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"TimeString","file":".","location":{"filename":"","line":77,"col":0,"byteIndex":1556},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"TimeStringSeconds","file":".","location":{"filename":"","line":97,"col":0,"byteIndex":2157},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"ViewVariable","file":".","location":{"filename":"","line":11,"col":0,"byteIndex":499},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Webserver","file":".","location":{"filename":"","line":5,"col":0,"byteIndex":145},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Websocket","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":289},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"raise","file":".","location":{"filename":"","line":38,"col":0,"byteIndex":927},"declarationKind":"export","deprecated":false}]}; + window.DENO_DOC_SEARCH_INDEX = {"nodes":[{"kind":["enum"],"name":"Algorithms","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":229},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Authenticator","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":95},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Cache","file":".","location":{"filename":"","line":10,"col":0,"byteIndex":211},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"CheckSource","file":".","location":{"filename":"","line":38,"col":0,"byteIndex":1093},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Configure","file":".","location":{"filename":"","line":9,"col":0,"byteIndex":227},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Controller","file":".","location":{"filename":"","line":15,"col":0,"byteIndex":574},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"CouchDB","file":".","location":{"filename":"","line":21,"col":0,"byteIndex":355},"declarationKind":"export","deprecated":false},{"kind":["function","namespace"],"name":"Cron","file":".","location":{"filename":"","line":56,"col":0,"byteIndex":2427},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"Cron.Cron","file":".","location":{"filename":"","line":325,"col":5,"byteIndex":9058},"declarationKind":"declare","deprecated":false},{"kind":["variable"],"name":"DEFAULT_OPTS","file":".","location":{"filename":"","line":52,"col":13,"byteIndex":1435},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Druid","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["enum"],"name":"ErrorCodes","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Events","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":102},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"ExclusionConfig","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":94},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"File","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Folder","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":47},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"GraphQL","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Hash","file":".","location":{"filename":"","line":50,"col":0,"byteIndex":1339},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"INSECURE_ALGORITHMS","file":".","location":{"filename":"","line":41,"col":13,"byteIndex":1177},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Inflector","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":63},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"InfluxDB","file":".","location":{"filename":"","line":16,"col":0,"byteIndex":184},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Logger","file":".","location":{"filename":"","line":44,"col":0,"byteIndex":1500},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Loki","file":".","location":{"filename":"","line":9,"col":0,"byteIndex":179},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Ntfy","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":48},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Nut","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":152},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"PASSWORD_DEFAULT","file":".","location":{"filename":"","line":8,"col":13,"byteIndex":247},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Password","file":".","location":{"filename":"","line":67,"col":0,"byteIndex":1718},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"PasswordOptions","file":".","location":{"filename":"","line":60,"col":0,"byteIndex":1549},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"QueryParameters","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":118},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Queue","file":".","location":{"filename":"","line":20,"col":0,"byteIndex":333},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"RCON","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":132},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Random","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Redis","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":148},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Request","file":".","location":{"filename":"","line":11,"col":0,"byteIndex":186},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"RequestParameters","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":48},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Router","file":".","location":{"filename":"","line":20,"col":0,"byteIndex":762},"declarationKind":"export","deprecated":false},{"kind":["enum"],"name":"StatusCodes","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Text","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Time","file":".","location":{"filename":"","line":5,"col":0,"byteIndex":242},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"TimeString","file":".","location":{"filename":"","line":84,"col":0,"byteIndex":1726},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"TimeStringSeconds","file":".","location":{"filename":"","line":111,"col":0,"byteIndex":2499},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"ViewVariable","file":".","location":{"filename":"","line":11,"col":0,"byteIndex":499},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Webserver","file":".","location":{"filename":"","line":5,"col":0,"byteIndex":145},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Websocket","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":289},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"raise","file":".","location":{"filename":"","line":38,"col":0,"byteIndex":927},"declarationKind":"export","deprecated":false}]}; })() \ No newline at end of file diff --git a/docs/~/Controller.html b/docs/~/Controller.html index 6b76f065..96b543ab 100644 --- a/docs/~/Controller.html +++ b/docs/~/Controller.html @@ -183,8 +183,8 @@

-
writeonly
-
deprecated
+
deprecated
+
writeonly
type
-
private
-
readonly
+
readonly
+
private
_componentDir: string
-
readonly
-
private
+
private
+
readonly
_templateDir: `./src/templates`
-
private
-
readonly
+
readonly
+
private
scheduler: Scheduler
-
private
-
readonly
+
readonly
+
private
time

Takes a time string and turns it into milliseconds

-
+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { TimeStringSeconds } from "https://deno.land/x/chomp/utility/time-string.ts";
+
+const milliseconds = TimeString`+1 minute`;
+
+
+
+
+
+
diff --git a/docs/~/TimeStringSeconds.html b/docs/~/TimeStringSeconds.html index 5cba3cb3..3c00a4e5 100644 --- a/docs/~/TimeStringSeconds.html +++ b/docs/~/TimeStringSeconds.html @@ -78,7 +78,73 @@

Takes a time string and turns it into round seconds

-
+
+
+ + + + + + + + + + +
+ +

Example 1

+
+
import { TimeStringSeconds } from "https://deno.land/x/chomp/utility/time-string.ts";
+
+const seconds = TimeStringSeconds`+1 minute`;
+
+
+
+
+
+
diff --git a/docs/~/Websocket.html b/docs/~/Websocket.html index 0c7f72d0..e6558519 100644 --- a/docs/~/Websocket.html +++ b/docs/~/Websocket.html @@ -183,8 +183,8 @@

-
private
-
readonly
+
readonly
+
private
authenticate: boolean
-
private
-
readonly
+
readonly
+
private
port: number
Date: Wed, 18 Sep 2024 17:16:19 +0200 Subject: [PATCH 221/379] Ignore docs while linting --- deno.json | 1 + 1 file changed, 1 insertion(+) diff --git a/deno.json b/deno.json index 9822b7b4..a01edba4 100644 --- a/deno.json +++ b/deno.json @@ -1,5 +1,6 @@ { "lint": { + "exclude": ["docs"], "rules": { "exclude": ["no-inferrable-types"] } From ab12f8ad0c2343b3ea570060b22e399493081e1f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 17:18:52 +0200 Subject: [PATCH 222/379] Fix Text test not running --- tests/util/{text.ts => text.test.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/util/{text.ts => text.test.ts} (100%) diff --git a/tests/util/text.ts b/tests/util/text.test.ts similarity index 100% rename from tests/util/text.ts rename to tests/util/text.test.ts From ddfa50d8304532054969e626ec185a7e9658a582 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 17:34:17 +0200 Subject: [PATCH 223/379] Test Text.tokenize --- tests/util/text.test.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/util/text.test.ts b/tests/util/text.test.ts index 5a0968a4..98ed58be 100644 --- a/tests/util/text.test.ts +++ b/tests/util/text.test.ts @@ -1,8 +1,18 @@ -import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; +import { assertEquals, assertNotEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; import { Text } from "../../utility/text.ts"; Deno.test("Text Test", async (t) => { - Deno.test("htmlentities", async (t) => { + await t.step("tokenize", () => { + // Test without limits + assertEquals(Text.tokenize("this is a sentence."), ["this", "is", "a", "sentence."]); + assertNotEquals(Text.tokenize("this is a sentence."), ["this", "is", "a sentence."]); + + // Test with limits + assertEquals(Text.tokenize("this is a sentence.", 2), ["this", "is", "a sentence."]); + assertNotEquals(Text.tokenize("this is a sentence.", 2), ["this", "is", "a", "sentence."]); + }) + + await t.step("htmlentities", () => { // Test all supported entities assertEquals(Text.htmlentities('&'), '&'); assertEquals(Text.htmlentities('<'), '<'); From 473f8bfbb58f8362bd3f8d55dab04ce1850ea707 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 17:45:48 +0200 Subject: [PATCH 224/379] Add linting to the pipeline --- .github/workflows/test.yml | 15 ++++++++++++++- deno.json | 10 +++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2cbe9c72..fba66710 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: uses: actions/checkout@v3 with: submodules: true - - name: Set up Deno + - name: Set up Deno uses: denoland/setup-deno@v1 with: deno-version: "1.40.0" @@ -31,3 +31,16 @@ jobs: deno-version: "1.40.0" - name: Run tests run: deno test --allow-read + fmt: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v3 + with: + submodules: true + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: "1.40.0" + - name: Run tests + run: deno fmt --check diff --git a/deno.json b/deno.json index a01edba4..90e02d35 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,14 @@ { + "fmt": { + "useTabs": false, + "singleQuote": false, + "semiColons": true, + "indentWidth": 2, + "lineWidth": 120, + "exclude": [".github",".idea","docs"] + }, "lint": { - "exclude": ["docs"], + "exclude": [".github",".idea","docs"], "rules": { "exclude": ["no-inferrable-types"] } From e006027e5a8ff1ce3e1c26e0afbe9c997d0769cc Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 17:48:44 +0200 Subject: [PATCH 225/379] Run fmt --- README.md | 25 +++++-- communication/couchdb.ts | 59 ++++++++--------- communication/druid.ts | 16 +++-- communication/graphql.ts | 24 +++---- communication/influxdb.ts | 36 +++++----- communication/loki.ts | 16 ++--- communication/ntfy.ts | 16 ++--- communication/nut.ts | 102 +++++++++++++++-------------- communication/rcon.ts | 6 +- communication/redis.ts | 10 +-- core/cache.ts | 28 ++++---- core/configure.ts | 20 +++--- core/logger.ts | 56 ++++++++++------ deno.json | 4 +- error/raise.ts | 9 ++- filesystem/file.ts | 21 +++--- filesystem/folder.ts | 10 +-- mod.ts | 6 +- queue/queue.ts | 54 ++++++++------- security/hash.ts | 28 ++++---- security/password.ts | 71 ++++++++++---------- security/random.ts | 6 +- tests/common/configure.test.ts | 22 +++---- tests/error/raise.test.ts | 10 +-- tests/queue/queue.test.ts | 78 +++++++++++----------- tests/util/inflector.test.ts | 24 +++---- tests/util/text.test.ts | 20 +++--- utility/check-source.ts | 28 ++++---- utility/empty.ts | 6 +- utility/inflector.ts | 15 ++--- utility/text.ts | 16 ++--- utility/time-string.ts | 9 +-- utility/time.ts | 42 ++++++++---- webserver/controller/component.ts | 4 +- webserver/controller/controller.ts | 44 +++++++------ webserver/http/request.ts | 66 ++++++++++++------- webserver/http/response-builder.ts | 62 +++++++++--------- webserver/http/status-codes.ts | 10 +-- webserver/pathToRegexp.ts | 51 +++++++-------- webserver/registry/registry.ts | 10 +-- webserver/renderers/handlebars.ts | 26 ++++---- webserver/routing/route.ts | 26 +++++--- webserver/routing/router.ts | 83 ++++++++++++----------- webserver/webserver.ts | 33 ++++++---- websocket/authenticator.ts | 6 +- websocket/events.ts | 14 ++-- websocket/websocket.ts | 40 +++++------ 47 files changed, 741 insertions(+), 627 deletions(-) diff --git a/README.md b/README.md index dcdda08d..632c8977 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,19 @@ # Chomp -Library of (arguably) useful stuff. -Should work just fine but comes with no warranties whatsoever. + +Library of (arguably) useful stuff.\ +Should work just fine but comes with no warranties whatsoever. ## Usage -Chomp is structured in such a way that you can import just what you need for your app. +Chomp is structured in such a way that you can import just what you need for your app.\ A good start would be to import the most common things you might use: + ```ts import * from "https://deno.land/x/chomp/common.ts"; ``` This includes (list might not always be up-to-date): + - [Cache](docs/core/cache.md) - [Configure](docs/core/configure.md) - [Logger](docs/logging/logger.md) @@ -21,25 +24,33 @@ This includes (list might not always be up-to-date): You can then import any of the "extras" as you need: - [Discord Bot](docs/discord/README.md) (Discordeno Wrapper): + ```ts import * from "https://deno.land/x/chomp/discord/mod.ts"; ``` + - [Webserver](docs/webserver/README.md): -```ts + +```ts import * from "https://deno.land/x/chomp/webserver/mod.ts"; ``` + - [Websocket Server](docs/websocket/README.md): -```ts + +```ts import * from "https://deno.land/x/chomp/websocket/mod.ts"; ``` -Additionally, you can explore the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what more Chomp is capable off! +Additionally, you can explore the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) +to see what more Chomp is capable off! -**NOTE**: While you can import `https://deno.land/x/chomp/mod.ts`, we advice against this as it'll load the entire codebase, including stuff you may not actually be using. +**NOTE**: While you can import `https://deno.land/x/chomp/mod.ts`, we advice against this as it'll load the entire +codebase, including stuff you may not actually be using. ## Versioning Versions adhere to the following versioning system of `x.y.z` where: + - `x` means a breaking change (eg. removal of a function, breaking upgrade of an upstream dependency etc.). - `y` means an addition or non-breaking update. - `z` means a typos, bug-fix etc. diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 10d96d1f..812ebf8c 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -7,8 +7,8 @@ export interface CouchResponse { status: number; statusText: string; // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - data: any|null; - error: null|{ + data: any | null; + error: null | { error: string; reason: string; }; @@ -19,10 +19,9 @@ interface CouchOverrides { } export class CouchDB { - private auth = ''; + private auth = ""; /** - * * @example * ```ts * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; @@ -42,9 +41,9 @@ export class CouchDB { * @param auth */ public constructor( - private readonly host: string = 'http://localhost:5984', + private readonly host: string = "http://localhost:5984", private readonly database: string, - auth: Auth = {username: '', password: ''}, + auth: Auth = { username: "", password: "" }, ) { this.auth = btoa(`${auth.username}:${auth.password}`); } @@ -65,7 +64,7 @@ export class CouchDB { */ public set username(username: string) { // Get the password from the data - const password = atob(this.auth).split(':')[1]; + const password = atob(this.auth).split(":")[1]; // Update auth string this.auth = btoa(`${username}:${password}`); @@ -87,7 +86,7 @@ export class CouchDB { */ public set password(password: string) { // Get the password from the data - const username = atob(this.auth).split(':')[0]; + const username = atob(this.auth).split(":")[0]; // Update auth string this.auth = btoa(`${username}:${password}`); @@ -139,7 +138,7 @@ export class CouchDB { */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public async insert(data: any): Promise { - return await this.raw('', data); + return await this.raw("", data); } /** @@ -167,10 +166,10 @@ export class CouchDB { // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public async update(id: string, revision: string, data: any): Promise { // Make sure the id and revision are set in the data - if(!data['_id'] || data['_id'] !== id) data['_id'] = id; - if(!data['_rev'] || data['_rev'] !== revision) data['_rev'] = revision; + if (!data["_id"] || data["_id"] !== id) data["_id"] = id; + if (!data["_rev"] || data["_rev"] !== revision) data["_rev"] = revision; - return await this.raw(id, data, { method: 'PUT' }); + return await this.raw(id, data, { method: "PUT" }); } /** @@ -197,14 +196,14 @@ export class CouchDB { public async upsert(id: string, data: any): Promise { // Check if a document already exists // Insert a new document if not - const exists = await this.raw(id, null, { method: 'GET' }); - if(exists.status === 404) { - data['_id'] = id; + const exists = await this.raw(id, null, { method: "GET" }); + if (exists.status === 404) { + data["_id"] = id; return await this.insert(data); } // Update the document - return await this.update(id, exists.data['_rev'], data); + return await this.update(id, exists.data["_rev"], data); } /** @@ -228,8 +227,8 @@ export class CouchDB { * @param id * @param revision */ - public async delete(id: string, revision: string): Promise { - return await this.raw(`${id}?rev=${revision}`, null, { method: 'DELETE' }); + public async delete(id: string, revision: string): Promise { + return await this.raw(`${id}?rev=${revision}`, null, { method: "DELETE" }); } /** @@ -250,7 +249,7 @@ export class CouchDB { * @param view * @param partition */ - public async viewDesign(design: string, view: string, partition: string): Promise{ + public async viewDesign(design: string, view: string, partition: string): Promise { return await this.raw(`_partition/${partition}/_design/${design}/_view/${view}`); } @@ -271,26 +270,26 @@ export class CouchDB { public async raw(endpoint: string, body: any = null, overrides: CouchOverrides = {}): Promise { // Start building opts const opts = { - method: overrides['method'] ? overrides['method'] : 'GET', + method: overrides["method"] ? overrides["method"] : "GET", headers: { Authorization: `Basic ${this.auth}`, - } + }, }; // Add body if specified - if(body !== null) { - opts['method'] = opts.method !== 'GET' ? opts.method : 'POST'; - opts['body'] = JSON.stringify(body); - opts.headers['Content-Type'] = 'application/json'; + if (body !== null) { + opts["method"] = opts.method !== "GET" ? opts.method : "POST"; + opts["body"] = JSON.stringify(body); + opts.headers["Content-Type"] = "application/json"; } // Make sure the endpoint starts with a leading slash - if(endpoint.charAt(0) !== '/' && endpoint !== '') endpoint = `/${endpoint}`; + if (endpoint.charAt(0) !== "/" && endpoint !== "") endpoint = `/${endpoint}`; // Send our request and get the response const resp = await fetch(`${this.host}/${this.database}${endpoint}`, opts); let data = null; - if(opts.method !== 'HEAD') data = await resp.json(); + if (opts.method !== "HEAD") data = await resp.json(); // Prepare our CouchResponse const couchResponse: CouchResponse = { @@ -301,10 +300,10 @@ export class CouchDB { }; // Check whether we have an error - if(resp.ok) { - couchResponse['data'] = data; + if (resp.ok) { + couchResponse["data"] = data; } else { - couchResponse['error'] = data; + couchResponse["error"] = data; } return couchResponse; diff --git a/communication/druid.ts b/communication/druid.ts index ab524a15..dd9ddb35 100644 --- a/communication/druid.ts +++ b/communication/druid.ts @@ -2,9 +2,13 @@ export class Druid { // deno-lint-ignore no-explicit-any -- TODO private spec: any = null; // deno-lint-ignore no-explicit-any -- TODO - public set setSpec(spec: any) { this.spec = spec; } + public set setSpec(spec: any) { + this.spec = spec; + } // deno-lint-ignore no-explicit-any -- TODO - public get getSpec(): any { return this.spec; } + public get getSpec(): any { + return this.spec; + } public constructor( private readonly host: string, @@ -17,13 +21,13 @@ export class Druid { * @returns Promise */ public async create(): Promise { - if(!this.spec) throw Error('No task specification has been set!'); + if (!this.spec) throw Error("No task specification has been set!"); return await fetch(`${this.host}/druid/indexer/v1/task`, { - method: 'POST', + method: "POST", body: this.spec, headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }); } } diff --git a/communication/graphql.ts b/communication/graphql.ts index df2ff599..7fedf597 100644 --- a/communication/graphql.ts +++ b/communication/graphql.ts @@ -1,24 +1,24 @@ export class GraphQL { private _variables = {}; - private _query: string = 'query{}'; - + private _query: string = "query{}"; + public constructor( - private readonly endpoint = '/graphql' + private readonly endpoint = "/graphql", ) { } - + public execute() { return fetch(this.endpoint, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' + "Content-Type": "application/json", + "Accept": "application/json", }, body: JSON.stringify({ query: this._query, - variables: this._variables - }) - }).then(r => r.json()); + variables: this._variables, + }), + }).then((r) => r.json()); } /** @@ -41,7 +41,7 @@ export class GraphQL { * @return The instance of this class */ public addVariable(key: string, value: string): GraphQL { - this._variables[key] = value; - return this; + this._variables[key] = value; + return this; } } diff --git a/communication/influxdb.ts b/communication/influxdb.ts index 706e6d98..d5148921 100644 --- a/communication/influxdb.ts +++ b/communication/influxdb.ts @@ -37,11 +37,11 @@ export class InfluxDB { * * @param data */ - public async write(data: Point|Point[]): Promise { + public async write(data: Point | Point[]): Promise { // Convert point(s) to Line Protocol entry - let points = ''; - if(Array.isArray(data)) { - for await(const point of data) { + let points = ""; + if (Array.isArray(data)) { + for await (const point of data) { points += `${point.toLine(this._api.precision)}\n`; } } else { @@ -53,13 +53,13 @@ export class InfluxDB { const resp = await fetch(this._api.url, { headers: { Authorization: this._api.auth, - 'Content-Type': 'text/plain', + "Content-Type": "text/plain", }, - method: 'POST', + method: "POST", body: points, }); return resp.ok; - } catch(e) { + } catch (e) { Logger.error(`Could not write point(s) to InfluxDB`, e.stack); return false; } @@ -68,8 +68,8 @@ export class InfluxDB { export class Point { private _tags: Map = new Map(); - private _fields: Map = new Map(); - private _timestamp: Date|number = 0; + private _fields: Map = new Map(); + private _timestamp: Date | number = 0; public constructor( private readonly measurement: string, @@ -93,7 +93,7 @@ export class Point { * @param key * @param value */ - public addField(key: string, value: string|number): this { + public addField(key: string, value: string | number): this { this._fields.set(key, value); return this; } @@ -105,38 +105,38 @@ export class Point { * * @param ts */ - public setTimestamp(ts: Date|number): this { + public setTimestamp(ts: Date | number): this { this._timestamp = ts; return this; } public toLine(precision: Precision = Precision.us): string { // Start off with a blank string - let line = ''; + let line = ""; // Set the measurement line += this.measurement; // Add all tags - for(const [key, value] of this._tags.entries()) { + for (const [key, value] of this._tags.entries()) { line += `,${key}=${value}`; } // Add separator before fieldset - line += ' '; + line += " "; // Add all fields const entries = []; - for(const [key, value] of this._fields.entries()) { + for (const [key, value] of this._fields.entries()) { entries.push(`${key}=${value}`); } - line += entries.join(','); + line += entries.join(","); // Add timestamp let ts = 0; - if(this._timestamp instanceof Date) { + if (this._timestamp instanceof Date) { ts = this._timestamp.getTime(); - switch(precision) { + switch (precision) { case Precision.s: ts = Math.trunc(ts / 1_000); break; diff --git a/communication/loki.ts b/communication/loki.ts index 7b3b19c3..3653325d 100644 --- a/communication/loki.ts +++ b/communication/loki.ts @@ -12,8 +12,8 @@ export class Loki { * @param tenant Tenant ID to use for the log item. Can be ommitted if not using multi-tenant mode. */ public constructor( - private readonly host: string = 'http://localhost:3100', - private readonly tenant: string = 'fake', + private readonly host: string = "http://localhost:3100", + private readonly tenant: string = "fake", ) { } @@ -22,20 +22,20 @@ export class Loki { * * @param stream */ - public async send(stream: LokiStream|LokiStream[]) { + public async send(stream: LokiStream | LokiStream[]) { try { const resp = await fetch(`${this.host}/loki/api/v1/push`, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json', - 'X-Scope-OrgID': this.tenant, + "Content-Type": "application/json", + "X-Scope-OrgID": this.tenant, }, body: JSON.stringify({ streams: Array.isArray(stream) ? stream : [stream], }), }); - if(resp.ok === false) throw Error(`Response non-OK: ${resp.statusText}`) - } catch(e) { + if (resp.ok === false) throw Error(`Response non-OK: ${resp.statusText}`); + } catch (e) { Logger.error(`Could not add message to Loki: ${e.message}`, e.stack); } } diff --git a/communication/ntfy.ts b/communication/ntfy.ts index 72b8cd15..5a6c55c8 100644 --- a/communication/ntfy.ts +++ b/communication/ntfy.ts @@ -4,8 +4,8 @@ export class Ntfy { public constructor( private readonly host: string, private readonly topic: string, - private readonly username: string = '', - private readonly password: string = '' + private readonly username: string = "", + private readonly password: string = "", ) { } @@ -18,16 +18,16 @@ export class Ntfy { try { const auth = btoa(`${this.username}:${this.password}`); const resp = await fetch(`${this.host}/${this.topic}`, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'text/plain', - 'Authorization': `Basic ${auth}` + "Content-Type": "text/plain", + "Authorization": `Basic ${auth}`, }, - body: message + body: message, }); - if(resp.status === 200) return; + if (resp.status === 200) return; throw Error(`${resp.status} - ${resp.statusText}`); - } catch(e) { + } catch (e) { Logger.error(`Could not send notification: "${e.message}"`, e.stack); } } diff --git a/communication/nut.ts b/communication/nut.ts index cda66296..b81f1c37 100644 --- a/communication/nut.ts +++ b/communication/nut.ts @@ -6,18 +6,20 @@ export class NutState { } export class Nut { - private host: string = ''; + private host: string = ""; private port: number = 3493; - private client: Deno.TcpConn|null = null; + private client: Deno.TcpConn | null = null; private _status: number = NutState.IDLE; // deno-lint-ignore no-explicit-any -- TODO private callback: any = null; - private dataBuf: string = ''; + private dataBuf: string = ""; - public get status(): number { return this._status; } + public get status(): number { + return this._status; + } - constructor(host: string|undefined, port: number = 3493) { - if(typeof host === 'undefined') { + constructor(host: string | undefined, port: number = 3493) { + if (typeof host === "undefined") { Logger.error(`Could not register monitor for "UPS": No NUT host defined!`); return this; } @@ -36,7 +38,7 @@ export class Nut { // deno-lint-ignore no-explicit-any -- TODO public async send(cmd: string, callback: any) { - if(this._status !== NutState.IDLE) throw new Error(`NUT not ready to send new data yet!`); + if (this._status !== NutState.IDLE) throw new Error(`NUT not ready to send new data yet!`); this._status = NutState.WAITING; this.callback = callback; @@ -60,8 +62,8 @@ export class Nut { } } - public getLoad(name: string|undefined): Promise { - if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + public getLoad(name: string | undefined): Promise { + if (typeof name === "undefined") Promise.reject("UPS name must be specified!"); // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO return new Promise(async (resolve: any) => { @@ -69,28 +71,28 @@ export class Nut { await this.send(`GET VAR ${name} ups.load`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) ups\.load "([0-9]+)"/.exec(data); - if(matches === null) { + if (matches === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } - if(typeof matches![1] === 'undefined' || matches![1] === null) { + if (typeof matches![1] === "undefined" || matches![1] === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(Number(matches![1])); }); }); } - public getPowerLimit(name: string|undefined): Promise { - if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + public getPowerLimit(name: string | undefined): Promise { + if (typeof name === "undefined") Promise.reject("UPS name must be specified!"); // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO return new Promise(async (resolve: any) => { @@ -98,27 +100,27 @@ export class Nut { await this.send(`GET VAR ${name} ups.realpower.nominal`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) ups\.realpower\.nominal "([0-9]+)"/.exec(data); - if(matches === null) { + if (matches === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } - if(typeof matches![1] === 'undefined' || matches![1] === null) { + if (typeof matches![1] === "undefined" || matches![1] === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(Number(matches![1])); }); }); } - public getCharge(name: string|undefined): Promise { - if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + public getCharge(name: string | undefined): Promise { + if (typeof name === "undefined") Promise.reject("UPS name must be specified!"); // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO return new Promise(async (resolve: any) => { @@ -126,27 +128,27 @@ export class Nut { await this.send(`GET VAR ${name} battery.charge`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) battery\.charge "([0-9]+)"/.exec(data); - if(matches === null) { + if (matches === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } - if(typeof matches![1] === 'undefined' || matches![1] === null) { + if (typeof matches![1] === "undefined" || matches![1] === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(Number(matches![1])); }); }); } - public getRuntime(name: string|undefined): Promise { - if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + public getRuntime(name: string | undefined): Promise { + if (typeof name === "undefined") Promise.reject("UPS name must be specified!"); // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO return new Promise(async (resolve: any) => { @@ -154,27 +156,27 @@ export class Nut { await this.send(`GET VAR ${name} battery.runtime`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) battery\.runtime "([0-9]+)"/.exec(data); - if(matches === null) { + if (matches === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } - if(typeof matches![1] === 'undefined' || matches![1] === null) { + if (typeof matches![1] === "undefined" || matches![1] === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(Number(matches![1])); }); }); } - public getStatus(name: string|undefined): Promise { - if(typeof name === 'undefined') Promise.reject('UPS name must be specified!'); + public getStatus(name: string | undefined): Promise { + if (typeof name === "undefined") Promise.reject("UPS name must be specified!"); // deno-lint-ignore no-explicit-any no-async-promise-executor -- TODO return new Promise(async (resolve: any) => { @@ -182,20 +184,20 @@ export class Nut { await this.send(`GET VAR ${name} ups.status`, (data: any) => { // Get our power const matches = /VAR (?:[a-zA-Z0-9]+) ups\.status "([0-9]+)"/.exec(data); - if(matches === null) { + if (matches === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } - if(typeof matches![1] === 'undefined' || matches![1] === null) { + if (typeof matches![1] === "undefined" || matches![1] === null) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(0); return; } this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(Number(matches![1])); }); }); @@ -206,14 +208,14 @@ export class Nut { return new Promise(async (resolve: any, reject: any) => { // deno-lint-ignore no-explicit-any -- TODO await this.send(`LIST UPS`, (data: any) => { - const dataArray = data.split('\n'); + const dataArray = data.split("\n"); // deno-lint-ignore no-explicit-any -- TODO const vars: any = {}; for (const line of dataArray) { // Check if we have an error - if(line.indexOf('ERR') === 0) { + if (line.indexOf("ERR") === 0) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; reject(line.slice(4)); return; } @@ -221,18 +223,18 @@ export class Nut { // Find UPS entries by regex // Check if 3 items have been found // Add them to our object - if(line.indexOf('UPS ') === 0) { + if (line.indexOf("UPS ") === 0) { const matches = /^UPS\s+(.+)\s+"(.*)"/.exec(line); - if(matches === null) continue; - if(matches.length < 3) continue; + if (matches === null) continue; + if (matches.length < 3) continue; vars[matches[1]] = matches[2]; continue; } // Resolve if we hit the end - if(line.indexOf('END LIST UPS') === 0) { + if (line.indexOf("END LIST UPS") === 0) { this._status = NutState.IDLE; - this.dataBuf = ''; + this.dataBuf = ""; resolve(vars); return; } diff --git a/communication/rcon.ts b/communication/rcon.ts index 2745fac0..d1d12852 100644 --- a/communication/rcon.ts +++ b/communication/rcon.ts @@ -15,13 +15,13 @@ export class RCON { * @param port * @param password Optional password for authentication */ - public async connect(ip: string, port: number, password: string|null = null) { + public async connect(ip: string, port: number, password: string | null = null) { this.conn = await Deno.connect({ hostname: ip, port: port, }); - if(password) await this.send(password, "AUTH"); + if (password) await this.send(password, "AUTH"); } /** @@ -97,6 +97,6 @@ export class RCON { str = str.substring(0, str.length - 1); } - return str.replace(/\0/g, '') || ""; + return str.replace(/\0/g, "") || ""; } } diff --git a/communication/redis.ts b/communication/redis.ts index d5f63e80..2fbe8987 100644 --- a/communication/redis.ts +++ b/communication/redis.ts @@ -1,8 +1,8 @@ -import { connect as redisConnect, Redis as RedisConn } from "https://deno.land/x/redis@v0.25.2/mod.ts" +import { connect as redisConnect, Redis as RedisConn } from "https://deno.land/x/redis@v0.25.2/mod.ts"; import { Logger } from "../core/logger.ts"; export class Redis { - private static connection: RedisConn|null = null; + private static connection: RedisConn | null = null; /** * Connect to a Redis node @@ -11,10 +11,10 @@ export class Redis { * @param port * @returns Promise */ - public static async connect(hostname = '127.0.0.1', port = 6379): Promise { + public static async connect(hostname = "127.0.0.1", port = 6379): Promise { Redis.connection = await redisConnect({ hostname: hostname, - port: port + port: port, }); } @@ -24,7 +24,7 @@ export class Redis { * @return any */ public static getConnection(): RedisConn { - if(!Redis.connection) Logger.error(`Redis connection requested before connecting!`); + if (!Redis.connection) Logger.error(`Redis connection requested before connecting!`); return Redis.connection!; } } diff --git a/core/cache.ts b/core/cache.ts index aebb0b7a..fe56f8f3 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -4,7 +4,7 @@ import { Cron } from "../utility/cron.ts"; interface CacheItem { data: unknown; - expires: Date|null; + expires: Date | null; } export class Cache { @@ -28,9 +28,9 @@ export class Cache { * @param value * @param expiry Can be set to null for never expiring items */ - public static set(key: string, value: unknown, expiry: string|null = '+1 minute'): void { + public static set(key: string, value: unknown, expiry: string | null = "+1 minute"): void { let expiresAt = null; - if(expiry) expiresAt = new Date(new Date().getTime() + TimeString`${expiry}`) + if (expiry) expiresAt = new Date(new Date().getTime() + TimeString`${expiry}`); Cache._items.set(key, { data: value, @@ -58,12 +58,12 @@ export class Cache { * @param key * @param optimistic Whether to serve expired items from the cache */ - public static get(key: string, optimistic = false): unknown|null { + public static get(key: string, optimistic = false): unknown | null { // Return null if the item doesn't exist - if(!Cache.exists(key)) return null; + if (!Cache.exists(key)) return null; // Return null if the item expired - if(Cache.expired(key) && !optimistic) return null; + if (Cache.expired(key) && !optimistic) return null; // Return the item's data return Cache._items.get(key)?.data; @@ -100,10 +100,10 @@ export class Cache { */ public static expired(key: string): boolean { // If the item doesn't exist, return true - if(!Cache.exists(key)) return true; + if (!Cache.exists(key)) return true; // Check if the expiry date is before our current date - if(!Cache._items.get(key)?.expires) return false; + if (!Cache._items.get(key)?.expires) return false; return Cache._items.get(key)?.expires! < new Date(); } @@ -121,7 +121,7 @@ export class Cache { * @param key * @param optimistic Whether to serve expired items from the cache */ - public static consume(key: string, optimistic = false): unknown|null { + public static consume(key: string, optimistic = false): unknown | null { // Copy item from cache const data = Cache.get(key, optimistic); @@ -183,21 +183,21 @@ export class Cache { const boundary = new Date(now.getTime() + TimeString`-1 hour -1 minute`); // Loop over each item in the cache - for(const [key, value] of Cache._items) { + for (const [key, value] of Cache._items) { // Keep items that do not expire - if(!value.expires) { + if (!value.expires) { Logger.debug(`Keeping cache item "${key}": Does not expire`); continue; } // Keep items that have not yet expired - if(value.expires >= start) { + if (value.expires >= start) { Logger.debug(`Keeping cache item "${key}": Has not expired`); continue; } // Keep items that may be served optimistically - if(value.expires >= boundary) { + if (value.expires >= boundary) { Logger.debug(`Keeping cache item "${key}": Keep for optimistic caching`); continue; } @@ -211,4 +211,4 @@ export class Cache { // Sweep cache every hour // @ts-ignore It's a function not a type -Cron('1 0 * * * *', () => Cache.sweep()); +Cron("1 0 * * * *", () => Cache.sweep()); diff --git a/core/configure.ts b/core/configure.ts index 4e687638..b988f082 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -2,8 +2,8 @@ import { Logger } from "./logger.ts"; // deno-lint-ignore no-explicit-any -- Arbitrary data may be used const defaults = new Map([ - ['debug', false], - ['error_log', `${Deno.cwd()}/logs/error.log`], + ["debug", false], + ["error_log", `${Deno.cwd()}/logs/error.log`], ]); export class Configure { @@ -26,13 +26,13 @@ export class Configure { */ public static async load(force = false): Promise { // Make sure we don't have loaded already - if(Configure.hasLoaded === true && force === false) return; + if (Configure.hasLoaded === true && force === false) return; Logger.info(`Loading data into Configure...`); // Make sure our file exists try { await Deno.stat(`${Deno.cwd()}/config.json`); - } catch(_e) { + } catch (_e) { Logger.warning(`Could not find file "config.json" at "${Deno.cwd()}". Configure will be empty!`); Configure.hasLoaded = true; return; @@ -42,10 +42,10 @@ export class Configure { try { const json = await Deno.readTextFile(`${Deno.cwd()}/config.json`); const data = JSON.parse(json); - for(const entry of Object.keys(data)) { + for (const entry of Object.keys(data)) { Configure.set(entry, data[entry]); } - } catch(e) { + } catch (e) { Logger.error(`Could not load JSON: "${e.message}"`, e.stack); return; } @@ -79,9 +79,9 @@ export class Configure { * @returns any|null */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - public static get(key: string, defaultValue: any = null): any|null { + public static get(key: string, defaultValue: any = null): any | null { // Return null if we do not have the key - if(!Configure.config.has(key)) return defaultValue; + if (!Configure.config.has(key)) return defaultValue; return Configure.config.get(key); } @@ -103,7 +103,7 @@ export class Configure { */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static set(key: string, value: any): void { - if(value === null || typeof value === 'undefined') return; + if (value === null || typeof value === "undefined") return; Configure.config.set(key, value); } @@ -150,7 +150,7 @@ export class Configure { // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static consume(key: string, defaultValue: any = null): any { // Check if the key exists, if not, return the default value - if(!Configure.config.has(key)) return defaultValue; + if (!Configure.config.has(key)) return defaultValue; // Hack together a reference to our item's value const ref = [Configure.config.get(key)]; diff --git a/core/logger.ts b/core/logger.ts index 5b306d22..9e945d1f 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -1,45 +1,49 @@ import { Time } from "../utility/time.ts"; import { Configure } from "./configure.ts"; -import { cyan, yellow, red, magenta, bold } from "https://deno.land/std@0.117.0/fmt/colors.ts"; +import { bold, cyan, magenta, red, yellow } from "https://deno.land/std@0.117.0/fmt/colors.ts"; type Handlers = { info: (message: string) => void; warning: (message: string) => void; - error: (message: string, stack: string|null) => void; + error: (message: string, stack: string | null) => void; debug: (message: string) => void; }; type LogLevels = keyof Handlers; const handlers: Handlers = { - info: (message: string): void => { console.log(`[${Logger.time()}] ${cyan('INFO')} > ${message}`); }, - warning: (message: string): void => { console.error(`[${Logger.time()}] ${yellow('WARN')} > ${message}`); }, - error: (message: string, stack:string|null = null): void => { + info: (message: string): void => { + console.log(`[${Logger.time()}] ${cyan("INFO")} > ${message}`); + }, + warning: (message: string): void => { + console.error(`[${Logger.time()}] ${yellow("WARN")} > ${message}`); + }, + error: (message: string, stack: string | null = null): void => { // Get current time const now = Logger.time(); // Check if we need to write to file // Write to file if need be - if(Configure.get('error_log')) { + if (Configure.get("error_log")) { try { let output = `[${now}] ERROR > ${message}`; - if(stack) output += `\r\n${stack}`; - Deno.writeTextFile(Configure.get('error_log'), output, {append: true}); - } catch(e) { + if (stack) output += `\r\n${stack}`; + Deno.writeTextFile(Configure.get("error_log"), output, { append: true }); + } catch (e) { console.error(`Could not append to error log: "${e.message}"`); } } // Write to console - let output = `[${now}] ${red(bold('ERROR'))} > ${message}`; - if(stack) output += `\r\n${stack}`; + let output = `[${now}] ${red(bold("ERROR"))} > ${message}`; + if (stack) output += `\r\n${stack}`; console.error(output); }, debug: (message: string): void => { - if(Configure.get('debug', false)) { - console.log(`[${Logger.time()}] ${magenta('DEBUG')} > ${message}`); + if (Configure.get("debug", false)) { + console.log(`[${Logger.time()}] ${magenta("DEBUG")} > ${message}`); } - } -} + }, +}; export class Logger { private static _handlers: Handlers = handlers; @@ -52,7 +56,9 @@ export class Logger { */ // @ts-ignore TODO: Figure out how to replace Function with something more sane // deno-lint-ignore ban-types -- TODO - public static setHandler(level: LogLevels, handler: Function): void { Logger._handlers[level] = handler; } + public static setHandler(level: LogLevels, handler: Function): void { + Logger._handlers[level] = handler; + } /** * Write an info message to the console @@ -60,7 +66,9 @@ export class Logger { * @param {string} message The message to write * @returns {void} */ - public static info(message: string): void { Logger._handlers['info'](message) } + public static info(message: string): void { + Logger._handlers["info"](message); + } /** * Write a warning message to the console @@ -68,7 +76,9 @@ export class Logger { * @param {string} message The message to write * @returns {void} */ - public static warning(message: string): void { Logger._handlers['warning'](message) } + public static warning(message: string): void { + Logger._handlers["warning"](message); + } /** * Write an error message to the console. @@ -78,7 +88,9 @@ export class Logger { * @param {string|null} stack Optional stacktrace * @returns {void} */ - public static error(message: string, stack: string|null = null): void { Logger._handlers['error'](message, stack); } + public static error(message: string, stack: string | null = null): void { + Logger._handlers["error"](message, stack); + } /** * Write a debug message to the console @@ -87,7 +99,9 @@ export class Logger { * @param {string} message The message to write * @returns {void} */ - public static debug(message: string): void { Logger._handlers['debug'](message); } + public static debug(message: string): void { + Logger._handlers["debug"](message); + } /** * Return the current time in format. @@ -98,6 +112,6 @@ export class Logger { * @returns {string} The formatted time */ public static time(): string { - return new Time().format(Configure.get('logger.timeformat', 'yyyy/MM/dd HH:mm:ss')); + return new Time().format(Configure.get("logger.timeformat", "yyyy/MM/dd HH:mm:ss")); } } diff --git a/deno.json b/deno.json index 90e02d35..7f383412 100644 --- a/deno.json +++ b/deno.json @@ -5,10 +5,10 @@ "semiColons": true, "indentWidth": 2, "lineWidth": 120, - "exclude": [".github",".idea","docs"] + "exclude": [".github", ".idea", "docs"] }, "lint": { - "exclude": [".github",".idea","docs"], + "exclude": [".github", ".idea", "docs"], "rules": { "exclude": ["no-inferrable-types"] } diff --git a/error/raise.ts b/error/raise.ts index 7893df0c..0362b23b 100644 --- a/error/raise.ts +++ b/error/raise.ts @@ -35,9 +35,12 @@ * @param err * @param type */ -export function raise(err: string, type: string|(new (err: string) => CustomError)|'Error' = 'Error'): never { +export function raise( + err: string, + type: string | (new (err: string) => CustomError) | "Error" = "Error", +): never { // Check if we want to throw a specific class - if(typeof type === 'function' && type.prototype instanceof Error) { + if (typeof type === "function" && type.prototype instanceof Error) { const e = new type(err); Error.captureStackTrace(e, raise); e.name = type.name; @@ -50,7 +53,7 @@ export function raise(err: string, type: string|(new Error.captureStackTrace(e, raise); // Check if we want to change the name - if(type !== "Error") e.name = (type as string).slice(-5).toLowerCase() !== "error" ? `${type}Error`: type as string; + if (type !== "Error") e.name = (type as string).slice(-5).toLowerCase() !== "error" ? `${type}Error` : type as string; // Throw the error throw e; diff --git a/filesystem/file.ts b/filesystem/file.ts index b67452bf..9cb4d116 100644 --- a/filesystem/file.ts +++ b/filesystem/file.ts @@ -1,38 +1,37 @@ export class File { - public constructor( - private readonly path: string + private readonly path: string, ) { } - + public async create(): Promise { await Deno.create(this.path); } - + public async exists(): Promise { try { const target = await Deno.stat(this.path); return target.isFile; - } catch(e) { - if(e instanceof Deno.errors.NotFound) return false; + } catch (e) { + if (e instanceof Deno.errors.NotFound) return false; throw e; } } - + public async delete(): Promise { await Deno.remove(this.path); } - + public ext(): string { const pos = this.path.lastIndexOf("."); - if(pos < 1) return ''; + if (pos < 1) return ""; return this.path.slice(pos + 1); } - + public async readTextFile() { return await Deno.readTextFile(this.path); } - + public async readFile() { return await Deno.readFile(this.path); } diff --git a/filesystem/folder.ts b/filesystem/folder.ts index 8f9eb5dd..a92b4d30 100644 --- a/filesystem/folder.ts +++ b/filesystem/folder.ts @@ -2,7 +2,7 @@ import { Logger } from "../core/logger.ts"; export class Folder { public constructor( - private readonly path: string + private readonly path: string, ) { } @@ -13,8 +13,8 @@ export class Folder { try { const target = await Deno.stat(this.path); return target.isDirectory; - } catch(e) { - if(e instanceof Deno.errors.NotFound) return false; + } catch (e) { + if (e instanceof Deno.errors.NotFound) return false; throw e; } } @@ -26,8 +26,8 @@ export class Folder { */ public async create(options?: Deno.MkdirOptions): Promise { try { - if(await this.exists()) throw new Error('The specified folder already exists!'); - } catch(e) { + if (await this.exists()) throw new Error("The specified folder already exists!"); + } catch (e) { Logger.warning(e.message); } diff --git a/mod.ts b/mod.ts index 1982c260..0af33b75 100644 --- a/mod.ts +++ b/mod.ts @@ -4,7 +4,7 @@ export { CouchDB } from "./communication/couchdb.ts"; export { Druid } from "./communication/druid.ts"; export { GraphQL } from "./communication/graphql.ts"; -export { InfluxDB } from "./communication/influxdb.ts" +export { InfluxDB } from "./communication/influxdb.ts"; export { Loki } from "./communication/loki.ts"; export { Ntfy } from "./communication/ntfy.ts"; export { Nut } from "./communication/nut.ts"; @@ -40,7 +40,7 @@ export { Hash } from "./security/hash.ts"; export { Password } from "./security/password.ts"; export { Random } from "./security/random.ts"; export type { Algorithms, INSECURE_ALGORITHMS } from "./security/hash.ts"; -export type { PASSWORD_DEFAULT, DEFAULT_OPTS, PasswordOptions } from "./security/password.ts"; +export type { DEFAULT_OPTS, PASSWORD_DEFAULT, PasswordOptions } from "./security/password.ts"; /** * Utility @@ -48,7 +48,7 @@ export type { PASSWORD_DEFAULT, DEFAULT_OPTS, PasswordOptions } from "./security export { CheckSource } from "./utility/check-source.ts"; export { Cron } from "./utility/cron.ts"; export { empty } from "./utility/empty.ts"; -export { Inflector} from "./utility/inflector.ts"; +export { Inflector } from "./utility/inflector.ts"; export { Text } from "./utility/text.ts"; export { Time } from "./utility/time.ts"; export { TimeString, TimeStringSeconds } from "./utility/time-string.ts"; diff --git a/queue/queue.ts b/queue/queue.ts index 8c9eb894..8cfc05e0 100644 --- a/queue/queue.ts +++ b/queue/queue.ts @@ -30,14 +30,18 @@ export class Queue { * * @returns number */ - public get count(): number { return this.items.length; } + public get count(): number { + return this.items.length; + } /** * Check whether the Queue has any items * * @returns boolean */ - public get isEmpty(): boolean { return this.items.length === 0; } + public get isEmpty(): boolean { + return this.items.length === 0; + } /** * Get the next item from the queue. @@ -45,9 +49,9 @@ export class Queue { * * @returns QueueItem */ - public get next(): QueueItem|null { + public get next(): QueueItem | null { // Make sure we have items in our queue - if(this.items.length === 0) return null; + if (this.items.length === 0) return null; // Return the first item in our queue and remove it // @ts-ignore We already return null when no items are present @@ -60,9 +64,9 @@ export class Queue { * * @returns QueueItem|null */ - public get peek(): QueueItem|null { + public get peek(): QueueItem | null { // Make sure we have items in our queue - if(this.items.length === 0) return null; + if (this.items.length === 0) return null; // Return the first item in our queue return this.items[0]; @@ -73,7 +77,9 @@ export class Queue { * * @returns QueueItems[] */ - public get dump(): QueueItem[] { return [...this.items]; } + public get dump(): QueueItem[] { + return [...this.items]; + } /** * Add an item to the queue based on the scheduler used @@ -82,32 +88,32 @@ export class Queue { */ public add(item: QueueItem): void { // Make sure data was set - if(Object.keys(item.data).length === 0) throw Error('Data for queue item may not be empty!'); + if (Object.keys(item.data).length === 0) throw Error("Data for queue item may not be empty!"); // Add item to the queue based on the scheduler used - switch(this.scheduler) { + switch (this.scheduler) { case Scheduler.FIFO: - if('weight' in item) { - Logger.debug('A weight was set without the weighted scheduler, removing it...'); + if ("weight" in item) { + Logger.debug("A weight was set without the weighted scheduler, removing it..."); delete item.weight; } this.items.push(item); break; case Scheduler.LIFO: - if('weight' in item) { - Logger.debug('A weight was set without the weighted scheduler, removing it...'); + if ("weight" in item) { + Logger.debug("A weight was set without the weighted scheduler, removing it..."); delete item.weight; } this.items.unshift(item); break; case Scheduler.WEIGHTED: - if(!('weight' in item)) { - Logger.debug('No weight was set with weighted scheduler, defaulting to 0...'); + if (!("weight" in item)) { + Logger.debug("No weight was set with weighted scheduler, defaulting to 0..."); item.weight = 0; } // Loop over all items in queue, add it at the bottom of it's weight - for (let i=0; i this.items[i].weight || i === this.items.length) { this.items.splice(i, 0, item); @@ -119,7 +125,7 @@ export class Queue { this.items.push(item); break; default: - throw Error('No scheduler has been set, this is a bug!'); + throw Error("No scheduler has been set, this is a bug!"); } } @@ -132,17 +138,17 @@ export class Queue { const itemKeys = Object.keys(item.data); const match = this.items.find((queued: QueueItem) => { // Check if the weights are the same - if(queued.weight !== item.weight) return false; + if (queued.weight !== item.weight) return false; // Check if all keys exists and if they have the same value - for(const key of itemKeys) { + for (const key of itemKeys) { // deno-lint-ignore no-prototype-builtins -- TODO - if(!queued.data.hasOwnProperty(key)) return false; - if(queued.data[key] !== item.data[key]) return false; + if (!queued.data.hasOwnProperty(key)) return false; + if (queued.data[key] !== item.data[key]) return false; } return true; }); - return typeof match !== 'undefined'; + return typeof match !== "undefined"; } /** @@ -150,5 +156,7 @@ export class Queue { * * @returns void */ - public clear(): void { this.items = []; } + public clear(): void { + this.items = []; + } } diff --git a/security/hash.ts b/security/hash.ts index ed3633e7..9421c968 100644 --- a/security/hash.ts +++ b/security/hash.ts @@ -5,14 +5,14 @@ import { crypto } from "https://deno.land/std@0.113.0/crypto/mod.ts"; * List of algorithms supported by this library */ export enum Algorithms { - SHA384 = 'SHA-384', - SHA3_224 = 'SHA3-224', - SHA3_256 = 'SHA3-256', - SHA3_384 = 'SHA3-384', - SHA3_512 = 'SHA3-512', - SHAKE128 = 'SHAKE128', - SHAKE256 = 'SHAKE256', - BLAKE2B256 = 'BLAKE2B-256', + SHA384 = "SHA-384", + SHA3_224 = "SHA3-224", + SHA3_256 = "SHA3-256", + SHA3_384 = "SHA3-384", + SHA3_512 = "SHA3-512", + SHAKE128 = "SHAKE128", + SHAKE256 = "SHAKE256", + BLAKE2B256 = "BLAKE2B-256", BLAKE2B384 = "BLAKE2B-384", BLAKE2B = "BLAKE2B", BLAKE2S = "BLAKE2S", @@ -24,15 +24,15 @@ export enum Algorithms { /* Insecure, please do not use in production */ RIPEMD160 = "RIPEMD-160", /* Insecure, please do not use in production */ - SHA224 = 'SHA-224', + SHA224 = "SHA-224", /* Insecure, please do not use in production */ - SHA256 = 'SHA-256', + SHA256 = "SHA-256", /* Insecure, please do not use in production */ - SHA512 = 'SHA-512', + SHA512 = "SHA-512", /* Insecure, please do not use in production */ - SHA1 = 'SHA-1', + SHA1 = "SHA-1", /* Insecure, please do not use in production */ - MD5 = 'MD5', + MD5 = "MD5", } /** @@ -92,6 +92,6 @@ export class Hash { * ``` */ public hex() { - return [...new Uint8Array(this.result)].map(x => x.toString(16).padStart(2, '0')).join(''); + return [...new Uint8Array(this.result)].map((x) => x.toString(16).padStart(2, "0")).join(""); } } diff --git a/security/password.ts b/security/password.ts index 30becf08..c372c782 100644 --- a/security/password.ts +++ b/security/password.ts @@ -15,34 +15,34 @@ export const PASSWORD_DEFAULT = Algorithms.SHA3_256; * - Prefix with "d" (to make linter happy) */ enum HASH_IDENTIFIERS { - 'd5e' = 'SHA-384', - 'd6d' = 'SHA3-224', - 'd88' = 'SHA3-256', - 'def' = 'SHA3-384', - 'd81' = 'SHA3-512', - 'dfa' = 'SHAKE128', - 'de3' = 'SHAKE256', - 'd34' = 'BLAKE2B-256', - 'd20' = 'BLAKE2B-384', - 'd85' = 'BLAKE2B', - 'd05' = "BLAKE2S", - 'd63' = "BLAKE3", - 'd87' = "KECCAK-224", - 'd78' = "KECCAK-256", - 'd1c' = "KECCAK-384", - 'df6' = "KECCAK-512", + "d5e" = "SHA-384", + "d6d" = "SHA3-224", + "d88" = "SHA3-256", + "def" = "SHA3-384", + "d81" = "SHA3-512", + "dfa" = "SHAKE128", + "de3" = "SHAKE256", + "d34" = "BLAKE2B-256", + "d20" = "BLAKE2B-384", + "d85" = "BLAKE2B", + "d05" = "BLAKE2S", + "d63" = "BLAKE3", + "d87" = "KECCAK-224", + "d78" = "KECCAK-256", + "d1c" = "KECCAK-384", + "df6" = "KECCAK-512", /* Insecure, please do not use in production */ - 'dc0' = 'RIPEMD-160', + "dc0" = "RIPEMD-160", /* Insecure, please do not use in production */ - 'dba' = 'SHA-224', + "dba" = "SHA-224", /* Insecure, please do not use in production */ - 'd45' = 'SHA-256', + "d45" = "SHA-256", /* Insecure, please do not use in production */ - 'db8' = 'SHA-512', + "db8" = "SHA-512", /* Insecure, please do not use in production */ - 'dc5' = 'SHA-1', + "dc5" = "SHA-1", /* Insecure, please do not use in production */ - 'db7' = 'MD5', + "db7" = "MD5", } /** @@ -51,8 +51,8 @@ enum HASH_IDENTIFIERS { */ export const DEFAULT_OPTS: PasswordOptions = { cost: 10, - allowInsecure: false -} + allowInsecure: false, +}; /** * Options for hashing a password @@ -73,16 +73,22 @@ export class Password { * @param options * @returns Hash string containing algo, cost, salt and hash */ - public static async hash(password: string, algo: Algorithms = PASSWORD_DEFAULT, options: PasswordOptions = DEFAULT_OPTS): Promise { + public static async hash( + password: string, + algo: Algorithms = PASSWORD_DEFAULT, + options: PasswordOptions = DEFAULT_OPTS, + ): Promise { // Make sure we are not using an insecure algorithm - if(INSECURE_ALGORITHMS.includes(algo) && !options.allowInsecure) throw Error('Insecure hashing algorithm selected, aborting.'); + if (INSECURE_ALGORITHMS.includes(algo) && !options.allowInsecure) { + throw Error("Insecure hashing algorithm selected, aborting."); + } // Make sure cost is set, else, use a default - if(typeof options.cost !== 'number' || options.cost <= 0) options.cost = DEFAULT_OPTS.cost; + if (typeof options.cost !== "number" || options.cost <= 0) options.cost = DEFAULT_OPTS.cost; // Get our identifier const identifierIndex = Object.values(HASH_IDENTIFIERS).indexOf(algo as unknown as HASH_IDENTIFIERS); - if(!identifierIndex) throw Error(`Identifier for algorithm "${algo}" could not be found!`); + if (!identifierIndex) throw Error(`Identifier for algorithm "${algo}" could not be found!`); const identifier = Object.keys(HASH_IDENTIFIERS)[identifierIndex]; // Create our hash @@ -94,7 +100,6 @@ export class Password { } /** - * * @param password Input password to check against * @param hash Hash string input from Password.hash() * @returns Promise Whether the password was valid or not @@ -102,13 +107,13 @@ export class Password { public static async verify(password: string, hash: string): Promise { // Split input hash at the delimiter // Then build our data - const tokens = hash.split('!'); - if(tokens.length < 4) throw Error('Malformed input hash'); + const tokens = hash.split("!"); + if (tokens.length < 4) throw Error("Malformed input hash"); const data = { algo: HASH_IDENTIFIERS[tokens[0] as keyof typeof HASH_IDENTIFIERS], cost: Number(tokens[1]), salt: tokens[2], - hash: tokens[3] + hash: tokens[3], }; // Create our hash @@ -121,7 +126,7 @@ export class Password { private static async doHash(input: string, algo: string, salt: string, cost: number): Promise { const rounds = 2 ** cost; let result = input; - for(let round = 0; round < rounds; round++) { + for (let round = 0; round < rounds; round++) { const h = new Hash(`${salt}${input}`, algo); await h.digest(); result = await h.hex(); diff --git a/security/random.ts b/security/random.ts index 7ea747c6..65a20555 100644 --- a/security/random.ts +++ b/security/random.ts @@ -37,7 +37,7 @@ export class Random { */ public static async string(length: number): Promise { const buf = await Random.bytes(length / 2); - return Array.from(buf, (dec: number) => dec.toString(16).padStart(2, "0")).join(''); + return Array.from(buf, (dec: number) => dec.toString(16).padStart(2, "0")).join(""); } /** @@ -105,9 +105,7 @@ export class Random { */ public static float(min = 0, max = 1, secure = false): number { // Generate our randomness - const random = secure - ? crypto.getRandomValues(new Uint32Array(1))[0] / Math.pow(2, 32) - : Math.random(); + const random = secure ? crypto.getRandomValues(new Uint32Array(1))[0] / Math.pow(2, 32) : Math.random(); // Limit and return return random * (max - min + 1) + min; diff --git a/tests/common/configure.test.ts b/tests/common/configure.test.ts index 7dfb3bd3..e7766797 100644 --- a/tests/common/configure.test.ts +++ b/tests/common/configure.test.ts @@ -3,26 +3,26 @@ import { Configure } from "../../core/configure.ts"; Deno.test("Configure Test", () => { // Add a test variable and test against it - Configure.set('test1', 'chomp'); - assertEquals(Configure.check('test1'), true); - assertEquals(Configure.get('test1'), 'chomp'); + Configure.set("test1", "chomp"); + assertEquals(Configure.check("test1"), true); + assertEquals(Configure.get("test1"), "chomp"); // Make sure consume works as intended - assertEquals(Configure.consume('test1'), 'chomp'); - assertEquals(Configure.check('test1'), false); + assertEquals(Configure.consume("test1"), "chomp"); + assertEquals(Configure.check("test1"), false); // Add a new test variable and immediately try to delete it - Configure.set('test2', 'chomp'); - Configure.delete('test2'); - assertEquals(Configure.check('test2'), false); + Configure.set("test2", "chomp"); + Configure.delete("test2"); + assertEquals(Configure.check("test2"), false); // Make sure clearing works - Configure.set('test3', 'chomp'); + Configure.set("test3", "chomp"); Configure.clear(); // deno-lint-ignore no-explicit-any -- Arbitrary data may be used assertEquals(Configure.dump(), new Map()); // Make sure default values work on get and consume - assertEquals(Configure.get('test4', 'default value'), 'default value'); - assertEquals(Configure.get('test5', 'default value'), 'default value'); + assertEquals(Configure.get("test4", "default value"), "default value"); + assertEquals(Configure.get("test5", "default value"), "default value"); }); diff --git a/tests/error/raise.test.ts b/tests/error/raise.test.ts index 04ccc994..266dec26 100644 --- a/tests/error/raise.test.ts +++ b/tests/error/raise.test.ts @@ -9,11 +9,11 @@ class CustomError extends Error { Deno.test("Errors Test", () => { // Check with a "simple" raise - assertThrows(() => raise('Some Error Message'), Error, 'Some Error Message'); - + assertThrows(() => raise("Some Error Message"), Error, "Some Error Message"); + // Check with custom Error type (via string) - assertThrows(() => raise('Some Error Message', 'CustomError'), Error, 'Some Error Message'); - + assertThrows(() => raise("Some Error Message", "CustomError"), Error, "Some Error Message"); + // Check with custom Error type (via class) - assertThrows(() => raise('Some Error Message', CustomError), CustomError, 'Some Error Message'); + assertThrows(() => raise("Some Error Message", CustomError), CustomError, "Some Error Message"); }); diff --git a/tests/queue/queue.test.ts b/tests/queue/queue.test.ts index 5f2c9eef..47a481d3 100644 --- a/tests/queue/queue.test.ts +++ b/tests/queue/queue.test.ts @@ -15,10 +15,10 @@ Deno.test("Queue Test", async (t) => { assertEquals(queue.next, null); // Add test items to the queue - queue.add({ data: { job: 'test1', } }); - queue.add({ data: { job: 'test2', } }); - queue.add({ data: { job: 'test3', } }); - queue.add({ data: { job: 'test4', } }); + queue.add({ data: { job: "test1" } }); + queue.add({ data: { job: "test2" } }); + queue.add({ data: { job: "test3" } }); + queue.add({ data: { job: "test4" } }); // Test isEmpty and count with items assertEquals(queue.isEmpty, false); @@ -28,31 +28,31 @@ Deno.test("Queue Test", async (t) => { queue.clear(); assertEquals(queue.isEmpty, true); assertEquals(queue.count, 0); - }) + }); await t.step("FIFO Scheduler", () => { // Create our queue const queue = new Queue(Scheduler.FIFO); // Add test items to the queue - queue.add({ data: { job: 'test1', } }); - queue.add({ data: { job: 'test2', } }); - queue.add({ data: { job: 'test3', } }); - queue.add({ data: { job: 'test4', } }); + queue.add({ data: { job: "test1" } }); + queue.add({ data: { job: "test2" } }); + queue.add({ data: { job: "test3" } }); + queue.add({ data: { job: "test4" } }); // Make sure peeking works without removal - assertEquals(queue.peek, { data: { job: 'test1', } }); + assertEquals(queue.peek, { data: { job: "test1" } }); assertEquals(queue.count, 4); // Make sure next works with removal - assertEquals(queue.next, { data: { job: 'test1', } }); + assertEquals(queue.next, { data: { job: "test1" } }); assertEquals(queue.count, 3); - assertEquals(queue.peek, { data: { job: 'test2', } }); + assertEquals(queue.peek, { data: { job: "test2" } }); // Make sure contains works - assertEquals(queue.contains({ data: { job: 'test2', } }), true); - assertEquals(queue.contains({ data: { job: 'test4', } }), true); - assertEquals(queue.contains({ data: { job: 'test5', } }), false); + assertEquals(queue.contains({ data: { job: "test2" } }), true); + assertEquals(queue.contains({ data: { job: "test4" } }), true); + assertEquals(queue.contains({ data: { job: "test5" } }), false); }); await t.step("LIFO Scheduler", () => { @@ -60,24 +60,24 @@ Deno.test("Queue Test", async (t) => { const queue = new Queue(Scheduler.LIFO); // Add test items to the queue - queue.add({ data: { job: 'test1', } }); - queue.add({ data: { job: 'test2', } }); - queue.add({ data: { job: 'test3', } }); - queue.add({ data: { job: 'test4', } }); + queue.add({ data: { job: "test1" } }); + queue.add({ data: { job: "test2" } }); + queue.add({ data: { job: "test3" } }); + queue.add({ data: { job: "test4" } }); // Make sure peeking works without removal - assertEquals(queue.peek, { data: { job: 'test4', } }); + assertEquals(queue.peek, { data: { job: "test4" } }); assertEquals(queue.count, 4); // Make sure next works with removal - assertEquals(queue.next, { data: { job: 'test4', } }); + assertEquals(queue.next, { data: { job: "test4" } }); assertEquals(queue.count, 3); - assertEquals(queue.peek, { data: { job: 'test3', } }); + assertEquals(queue.peek, { data: { job: "test3" } }); // Make sure contains works - assertEquals(queue.contains({ data: { job: 'test1', } }), true); - assertEquals(queue.contains({ data: { job: 'test3', } }), true); - assertEquals(queue.contains({ data: { job: 'test5', } }), false); + assertEquals(queue.contains({ data: { job: "test1" } }), true); + assertEquals(queue.contains({ data: { job: "test3" } }), true); + assertEquals(queue.contains({ data: { job: "test5" } }), false); }); await t.step("WEIGHTED Scheduler", () => { @@ -85,28 +85,28 @@ Deno.test("Queue Test", async (t) => { const queue = new Queue(Scheduler.WEIGHTED); // Add test items to the queue - queue.add({ weight: 0, data: { job: 'test1', } }); - queue.add({ weight: 0, data: { job: 'test2', } }); - queue.add({ weight: 1, data: { job: 'test3', } }); - queue.add({ weight: 2, data: { job: 'test4', } }); - queue.add({ weight: 3, data: { job: 'test5', } }); - queue.add({ data: { job: 'test6', } }); + queue.add({ weight: 0, data: { job: "test1" } }); + queue.add({ weight: 0, data: { job: "test2" } }); + queue.add({ weight: 1, data: { job: "test3" } }); + queue.add({ weight: 2, data: { job: "test4" } }); + queue.add({ weight: 3, data: { job: "test5" } }); + queue.add({ data: { job: "test6" } }); // Make sure peeking works without removal - assertEquals(queue.peek, { weight: 3, data: { job: 'test5', } }); + assertEquals(queue.peek, { weight: 3, data: { job: "test5" } }); assertEquals(queue.count, 6); // Make sure next works with removal - assertEquals(queue.next, { weight: 3, data: { job: 'test5', } }); + assertEquals(queue.next, { weight: 3, data: { job: "test5" } }); assertEquals(queue.count, 5); - assertEquals(queue.peek, { weight: 2, data: { job: 'test4', } }); + assertEquals(queue.peek, { weight: 2, data: { job: "test4" } }); // Make sure contains works - assertEquals(queue.contains({ weight: 0, data: { job: 'test1', } }), true); - assertEquals(queue.contains({ weight: 1, data: { job: 'test3', } }), true); - assertEquals(queue.contains({ weight: 2, data: { job: 'test3', } }), false); + assertEquals(queue.contains({ weight: 0, data: { job: "test1" } }), true); + assertEquals(queue.contains({ weight: 1, data: { job: "test3" } }), true); + assertEquals(queue.contains({ weight: 2, data: { job: "test3" } }), false); // Make sure we didn't add "weightless" items - assertEquals(queue.contains({ data: { job: 'test6', } }), false); + assertEquals(queue.contains({ data: { job: "test6" } }), false); }); -}) +}); diff --git a/tests/util/inflector.test.ts b/tests/util/inflector.test.ts index 414f6446..6a80edba 100644 --- a/tests/util/inflector.test.ts +++ b/tests/util/inflector.test.ts @@ -3,26 +3,26 @@ import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; Deno.test("Inflector Test", async (t) => { await t.step("ucfirst", () => { - assertEquals(Inflector.ucfirst('hello world'), 'Hello world'); - assertEquals(Inflector.ucfirst('hello World'), 'Hello World'); + assertEquals(Inflector.ucfirst("hello world"), "Hello world"); + assertEquals(Inflector.ucfirst("hello World"), "Hello World"); }); await t.step("lcfirst", () => { - assertEquals(Inflector.lcfirst('Hello world'), 'hello world'); - assertEquals(Inflector.lcfirst('Hello World'), 'hello World'); + assertEquals(Inflector.lcfirst("Hello world"), "hello world"); + assertEquals(Inflector.lcfirst("Hello World"), "hello World"); }); await t.step("pascalize", () => { - assertEquals(Inflector.pascalize('hello-world'), 'Hello-world'); - assertEquals(Inflector.pascalize('hello_World'), 'HelloWorld'); - assertEquals(Inflector.pascalize('hello-world', '-'), 'HelloWorld'); - assertEquals(Inflector.pascalize('hello_World', '-'), 'Hello_World'); + assertEquals(Inflector.pascalize("hello-world"), "Hello-world"); + assertEquals(Inflector.pascalize("hello_World"), "HelloWorld"); + assertEquals(Inflector.pascalize("hello-world", "-"), "HelloWorld"); + assertEquals(Inflector.pascalize("hello_World", "-"), "Hello_World"); }); await t.step("humanize", () => { - assertEquals(Inflector.humanize('hello-world'), 'Hello-world'); - assertEquals(Inflector.humanize('hello_World'), 'Hello World'); - assertEquals(Inflector.humanize('hello-world', '-'), 'Hello World'); - assertEquals(Inflector.humanize('hello_World', '-'), 'Hello_World'); + assertEquals(Inflector.humanize("hello-world"), "Hello-world"); + assertEquals(Inflector.humanize("hello_World"), "Hello World"); + assertEquals(Inflector.humanize("hello-world", "-"), "Hello World"); + assertEquals(Inflector.humanize("hello_World", "-"), "Hello_World"); }); }); diff --git a/tests/util/text.test.ts b/tests/util/text.test.ts index 98ed58be..73fd12fc 100644 --- a/tests/util/text.test.ts +++ b/tests/util/text.test.ts @@ -10,20 +10,20 @@ Deno.test("Text Test", async (t) => { // Test with limits assertEquals(Text.tokenize("this is a sentence.", 2), ["this", "is", "a sentence."]); assertNotEquals(Text.tokenize("this is a sentence.", 2), ["this", "is", "a", "sentence."]); - }) + }); await t.step("htmlentities", () => { // Test all supported entities - assertEquals(Text.htmlentities('&'), '&'); - assertEquals(Text.htmlentities('<'), '<'); - assertEquals(Text.htmlentities('>'), '>'); - assertEquals(Text.htmlentities('\''), '''); - assertEquals(Text.htmlentities('"'), '"'); + assertEquals(Text.htmlentities("&"), "&"); + assertEquals(Text.htmlentities("<"), "<"); + assertEquals(Text.htmlentities(">"), ">"); + assertEquals(Text.htmlentities("'"), "'"); + assertEquals(Text.htmlentities('"'), """); // Test regular characters - assertEquals(Text.htmlentities('1'), '1'); - assertEquals(Text.htmlentities('2'), '2'); - assertEquals(Text.htmlentities('a'), 'a'); - assertEquals(Text.htmlentities('b'), 'b'); + assertEquals(Text.htmlentities("1"), "1"); + assertEquals(Text.htmlentities("2"), "2"); + assertEquals(Text.htmlentities("a"), "a"); + assertEquals(Text.htmlentities("b"), "b"); }); }); diff --git a/utility/check-source.ts b/utility/check-source.ts index eb6d1b3e..704e8670 100644 --- a/utility/check-source.ts +++ b/utility/check-source.ts @@ -41,12 +41,12 @@ export class CheckSource { constructor( private readonly paths: string[], - private readonly exclusions: ExclusionConfig = { directories: [], files: [] } + private readonly exclusions: ExclusionConfig = { directories: [], files: [] }, ) {} public async run(): Promise { // Get all files in all paths - for(const path of this.paths) { + for (const path of this.paths) { await this.getFiles(path); } @@ -55,8 +55,10 @@ export class CheckSource { await this.checkFiles(); // Exit when done - if(this.errors > 0) { - Logger.info(`Finished checking files with ${this.errors} errors!\r\nPlease check the logs above for more information.`); + if (this.errors > 0) { + Logger.info( + `Finished checking files with ${this.errors} errors!\r\nPlease check the logs above for more information.`, + ); Deno.exit(1); } Logger.info(`Finished checking files without errors!`); @@ -71,21 +73,21 @@ export class CheckSource { */ private async getFiles(path: string) { Logger.info(`Getting all files in directory "${path}"...`); - for await(const entry of Deno.readDir(path)) { - if(entry.isDirectory) { - if('directories' in this.exclusions && this.exclusions.directories?.includes(entry.name)) { + for await (const entry of Deno.readDir(path)) { + if (entry.isDirectory) { + if ("directories" in this.exclusions && this.exclusions.directories?.includes(entry.name)) { Logger.debug(`Skipping excluded directory "${path}/${entry.name}"...`); continue; } await this.getFiles(`${path}/${entry.name}`); } - if(entry.isFile) { - if('files' in this.exclusions && this.exclusions.files?.includes(entry.name)) { + if (entry.isFile) { + if ("files" in this.exclusions && this.exclusions.files?.includes(entry.name)) { Logger.debug(`Skipping excluded file "${path}/${entry.name}"...`); continue; } - if(new File(`${path}/${entry.name}`).ext() !== 'ts') { + if (new File(`${path}/${entry.name}`).ext() !== "ts") { Logger.debug(`Skipping non-ts file...`); continue; } @@ -101,7 +103,7 @@ export class CheckSource { * @param path */ private addFile(path: string) { - if(this.files.includes(path)) return; + if (this.files.includes(path)) return; this.files.push(path); } @@ -109,10 +111,10 @@ export class CheckSource { * Check all files found */ private async checkFiles() { - for await(const file of this.files) { + for await (const file of this.files) { try { await import(`file://${Deno.cwd()}/${file}`); - } catch(e) { + } catch (e) { Logger.error(`Check for "${Deno.cwd()}/${file}" failed: ${e.message}`, e.stack); this.errors++; } diff --git a/utility/empty.ts b/utility/empty.ts index d768262b..5cc177b9 100644 --- a/utility/empty.ts +++ b/utility/empty.ts @@ -5,8 +5,8 @@ * @returns boolean */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used -export default function empty(input: string|any[]|null): boolean { - if(!input) return true; - if(typeof input === "string") return input === ""; +export default function empty(input: string | any[] | null): boolean { + if (!input) return true; + if (typeof input === "string") return input === ""; return input.length === 0; } diff --git a/utility/inflector.ts b/utility/inflector.ts index 489b80e5..32b6e0e3 100644 --- a/utility/inflector.ts +++ b/utility/inflector.ts @@ -2,7 +2,6 @@ * Idea and code primarily based on CakePHP's code. */ export class Inflector { - /** * Return input string with first character uppercased. * @@ -27,19 +26,19 @@ export class Inflector { * @param input * @param delimiter Optional delimiter by which to split the string */ - public static pascalize(input: string, delimiter: string = '_'): string { + public static pascalize(input: string, delimiter: string = "_"): string { return this .humanize(input, delimiter) - .replaceAll(' ', ''); + .replaceAll(" ", ""); } /** * Turn a string into camelCase - * + * * @param input * @param delimiter Optional delimiter by which to split the string */ - public static camelize(input: string, delimiter: string = '_'): string { + public static camelize(input: string, delimiter: string = "_"): string { return this.lcfirst(this.pascalize(input, delimiter)); } @@ -50,17 +49,17 @@ export class Inflector { * @param input * @param delimiter */ - public static humanize(input: string, delimiter: string = '_'): string { + public static humanize(input: string, delimiter: string = "_"): string { // Split our string into tokens const tokens: string[] = input .split(delimiter); // Uppercase each of the tokens - for(let i = 0; i < tokens.length; i++) { + for (let i = 0; i < tokens.length; i++) { tokens[i] = this.ucfirst(tokens[i]); } // Join tokens into a string and return - return tokens.join(' '); + return tokens.join(" "); } } diff --git a/utility/text.ts b/utility/text.ts index 9b983d0f..7545d419 100644 --- a/utility/text.ts +++ b/utility/text.ts @@ -8,13 +8,13 @@ export class Text { /** * Tokenize a string into an array of strings. - * + * * @param input * @param limit */ public static tokenize(input: string, limit = 3): string[] { const tokens = input.split(" "); - if(tokens.length > limit) { + if (tokens.length > limit) { const ret = tokens.splice(0, limit); ret.push(tokens.join(" ")); return ret; @@ -32,11 +32,11 @@ export class Text { */ public static htmlentities(str: string): string { return str.replace(/[&<>'"]/g, (tag: string) => ({ - '&': '&', - '<': '<', - '>': '>', - "'": ''', - '"': '"', - }[tag] ?? tag)) + "&": "&", + "<": "<", + ">": ">", + "'": "'", + '"': """, + }[tag] ?? tag)); } } diff --git a/utility/time-string.ts b/utility/time-string.ts index e2f11d78..942182d0 100644 --- a/utility/time-string.ts +++ b/utility/time-string.ts @@ -7,7 +7,7 @@ interface RegExp { groups: { digit: number; format: string; - } + }; } const TimeRegexp = /(?[+-]?\d+(\.\d+)?)\s*(?[a-zA-Z]+)/g; @@ -28,7 +28,7 @@ const year = month * 12; */ function parseNumberFormat(digit: string, unit: string): number { const n = Number(digit); - switch(unit) { + switch (unit) { case "ms": case "millisecond": case "milliseconds": @@ -82,10 +82,11 @@ function parseNumberFormat(digit: string, unit: string): number { */ // deno-lint-ignore no-explicit-any -- TODO export function TimeString(strIn: TemplateStringsArray, ...parts: any[]): number { - const str = String.raw(strIn, parts).toLowerCase().replace(/\s/g, ''); + const str = String.raw(strIn, parts).toLowerCase().replace(/\s/g, ""); const parsed = [...str.matchAll(TimeRegexp)]; - if (parsed.length === 0) + if (parsed.length === 0) { throw new Error(`"${str}" is not a valid interval string`); + } let out = 0; for (const res of parsed) { out += Math.round(parseNumberFormat(res.groups!.value, res.groups!.unit)); diff --git a/utility/time.ts b/utility/time.ts index 3052ac70..22526246 100644 --- a/utility/time.ts +++ b/utility/time.ts @@ -4,18 +4,36 @@ import { TimeString } from "./time-string.ts"; export class Time { private readonly time; - public get getTime() { return this.time; } - public get milliseconds() { return this.time.getMilliseconds(); } - public get seconds() { return this.time.getSeconds(); } - public get minutes() { return this.time.getMinutes(); } - public get hours() { return this.time.getHours(); } - public get weekDay() { return this.time.getDay(); } - public get monthDay() { return this.time.getDate(); } - public get month() { return this.time.getMonth(); } - public get year() { return this.time.getFullYear(); } + public get getTime() { + return this.time; + } + public get milliseconds() { + return this.time.getMilliseconds(); + } + public get seconds() { + return this.time.getSeconds(); + } + public get minutes() { + return this.time.getMinutes(); + } + public get hours() { + return this.time.getHours(); + } + public get weekDay() { + return this.time.getDay(); + } + public get monthDay() { + return this.time.getDate(); + } + public get month() { + return this.time.getMonth(); + } + public get year() { + return this.time.getFullYear(); + } - public constructor(time: string|undefined = undefined) { - this.time = timets(time).tz(Deno.env.get('TZ')!).t; + public constructor(time: string | undefined = undefined) { + this.time = timets(time).tz(Deno.env.get("TZ")!).t; } public format(format: string) { @@ -23,7 +41,7 @@ export class Time { } public midnight() { - this.time.setHours(0,0,0,0); + this.time.setHours(0, 0, 0, 0); return this; } diff --git a/webserver/controller/component.ts b/webserver/controller/component.ts index 47221e8c..84a65b0d 100644 --- a/webserver/controller/component.ts +++ b/webserver/controller/component.ts @@ -2,10 +2,10 @@ import { Controller } from "./controller.ts"; export class Component { public constructor( - private readonly controller: Controller + private readonly controller: Controller, ) { } - + protected getController(): typeof this.controller { return this.controller; } diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index a87d3166..b4d76efe 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -9,14 +9,14 @@ import { Registry } from "../registry/registry.ts"; import { compress as compressBrotli } from "https://deno.land/x/brotli@v0.1.4/mod.ts"; export interface ViewVariable { - [key: string]: string|number|unknown; + [key: string]: string | number | unknown; } export class Controller { private static readonly _templateDir = `./src/templates`; private static readonly _componentDir = `file:///${Deno.cwd()}/src/controller/component`; private _response: ResponseBuilder = new ResponseBuilder(); - private _vars: ViewVariable = {}; + private _vars: ViewVariable = {}; /** * Set the 'Content-Type' header @@ -24,9 +24,11 @@ export class Controller { * @deprecated Please use "Controller.getResponse().withType()" instead. * @param value */ - public set type(value = 'text/html') { - Logger.warning('Setting type on controller itself is deprecated, please use "Controller.getResponse().withType()" instead.'); - this.getResponse().withHeader('Content-Type', value); + public set type(value = "text/html") { + Logger.warning( + 'Setting type on controller itself is deprecated, please use "Controller.getResponse().withType()" instead.', + ); + this.getResponse().withHeader("Content-Type", value); } constructor( @@ -63,7 +65,7 @@ export class Controller { protected async loadComponent(name: string): Promise { // Check if we already loaded the component before // Use that if so - if(Registry.has(`${Inflector.ucfirst(name)}Component`)) { + if (Registry.has(`${Inflector.ucfirst(name)}Component`)) { const module = Registry.get(`${Inflector.ucfirst(name)}Component`); this[Inflector.ucfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); return this; @@ -73,12 +75,12 @@ export class Controller { const module = await import(`${Controller._componentDir}/${Inflector.lcfirst(name)}.ts`); // Make sure the component class was found - if(!(`${Inflector.ucfirst(name)}Component` in module)) { + if (!(`${Inflector.ucfirst(name)}Component` in module)) { raise(`No class "${Inflector.ucfirst(name)}Component" could be found.`); } // Make sure the component class extends our base controller - if(!(module[`${Inflector.ucfirst(name)}Component`].prototype instanceof Component)) { + if (!(module[`${Inflector.ucfirst(name)}Component`].prototype instanceof Component)) { raise(`Class "${Inflector.ucfirst(name)}Component" does not properly extend Chomp's component.`); } @@ -97,7 +99,9 @@ export class Controller { * @param key * @param value */ - protected set(key: string, value: string|number|unknown) { this._vars[key] = value; } + protected set(key: string, value: string | number | unknown) { + this._vars[key] = value; + } /** * Render the page output @@ -106,36 +110,36 @@ export class Controller { * @returns Promise */ public async render(): Promise { - let body: string|Uint8Array = ''; + let body: string | Uint8Array = ""; const canCompress = true; - switch(this.getResponse().getHeaderLine('Content-Type').toLowerCase()) { - case 'application/json': { - body = JSON.stringify(this._vars['data']); + switch (this.getResponse().getHeaderLine("Content-Type").toLowerCase()) { + case "application/json": { + body = JSON.stringify(this._vars["data"]); break; } - case 'text/plain': { - body = this._vars['message'] as string; + case "text/plain": { + body = this._vars["message"] as string; break; } - case 'text/html': { + case "text/html": { const controller = Inflector.lcfirst(this.getRequest().getRoute().getController()); const action = this.getRequest().getRoute().getAction(); body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars); break; } - case 'application/octet-stream': { - body = this._vars['data'] as Uint8Array; + case "application/octet-stream": { + body = this._vars["data"] as Uint8Array; break; } } // Check if we can compress with Brotli // TODO: Hope that Deno will make this obsolete. - if(this.getRequest().getHeaders().get('accept-encoding')?.includes('br') && canCompress && body.length > 1024) { + if (this.getRequest().getHeaders().get("accept-encoding")?.includes("br") && canCompress && body.length > 1024) { Logger.debug(`Compressing body with brotli: ${body.length}-bytes`); body = compressBrotli(new TextEncoder().encode(body)); Logger.debug(`Compressed body with brotli: ${body.length}-bytes`); - this.getResponse().withHeader('Content-Encoding', 'br'); + this.getResponse().withHeader("Content-Encoding", "br"); } // Set our final body diff --git a/webserver/http/request.ts b/webserver/http/request.ts index 61ec60fb..2487d529 100644 --- a/webserver/http/request.ts +++ b/webserver/http/request.ts @@ -18,35 +18,53 @@ export class Request { private readonly params: RequestParameters, private readonly query: QueryParameters, private readonly auth: string, - private readonly ip: string|null = null, + private readonly ip: string | null = null, ) { } - - public getUrl(): string { return this.url; } - - public getMethod(): string { return this.method; } - - public getRoute(): Route { return this.route; } - - public getHeaders(): Headers { return this.headers ;} - - public getBody(): string { return this.body; } - - public getParams(): RequestParameters { return this.params; } - - public getParam(name: string): string|null { - if(name in this.params) return this.params[name]; + + public getUrl(): string { + return this.url; + } + + public getMethod(): string { + return this.method; + } + + public getRoute(): Route { + return this.route; + } + + public getHeaders(): Headers { + return this.headers; + } + + public getBody(): string { + return this.body; + } + + public getParams(): RequestParameters { + return this.params; + } + + public getParam(name: string): string | null { + if (name in this.params) return this.params[name]; return null; } - public getQueryParams(): QueryParameters { return this.query; } - - public getQuery(name: string): string|null { - if(name in this.query) return this.query[name]; + public getQueryParams(): QueryParameters { + return this.query; + } + + public getQuery(name: string): string | null { + if (name in this.query) return this.query[name]; return null; } - - public getAuth(): string { return this.auth; } - - public getIp(): string|null { return this.ip; } + + public getAuth(): string { + return this.auth; + } + + public getIp(): string | null { + return this.ip; + } } diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts index 62ade900..883c12cd 100644 --- a/webserver/http/response-builder.ts +++ b/webserver/http/response-builder.ts @@ -8,11 +8,11 @@ interface ResponseHeader { export class ResponseBuilder { private readonly _headers: Map> = new Map>(); private _status: StatusCodes = StatusCodes.OK; - private _body = ''; - + private _body = ""; + public constructor() { // Set default headers - this.withHeader('Content-Type', 'text/html'); + this.withHeader("Content-Type", "text/html"); } /** @@ -25,7 +25,7 @@ export class ResponseBuilder { /** * Get a header as an array. * Use ResponseBuilder.getHeaderLine() if wanted as a string instead. - * + * * @param name */ public getHeader(name: string): string[] { @@ -34,17 +34,17 @@ export class ResponseBuilder { /** * Get a header as a string. - * + * * @param name */ public getHeaderLine(name: string): string { const header = this.getHeader(name); - return header.join(', '); + return header.join(", "); } /** * Check if a header is set. - * + * * @param name */ public hasHeader(name: string): boolean { @@ -54,7 +54,7 @@ export class ResponseBuilder { /** * Set a header, overriding the old value. * Use ResponseBuilder.withAddedHeader() if you want to set multiple values. - * + * * @param name * @param value */ @@ -66,7 +66,7 @@ export class ResponseBuilder { /** * Add a value to our headers. * Use ResponseBuilder.withHeader() if you want to override it instead. - * + * * @param name * @param value */ @@ -74,30 +74,30 @@ export class ResponseBuilder { // Check if we have existing headers // If not, start with an empty array const existing = this._headers.get(name) ?? []; - + // Add our value existing.push(value); - + // Save our header this._headers.set(name, existing); - + // Return this route builder return this; } /** * Set the response MIME - * + * * @param mime */ - public withType(mime = 'text/html'): ResponseBuilder { - this.withHeader('Content-Type', mime); + public withType(mime = "text/html"): ResponseBuilder { + this.withHeader("Content-Type", mime); return this; } /** * Set our response status. - * + * * @param status */ public withStatus(status: StatusCodes = StatusCodes.OK): ResponseBuilder { @@ -107,7 +107,7 @@ export class ResponseBuilder { /** * Set our response body. - * + * * @param body */ public withBody(body: string): ResponseBuilder { @@ -120,14 +120,14 @@ export class ResponseBuilder { * * @param duration */ - public withCache(duration = '+1 day'): ResponseBuilder { + public withCache(duration = "+1 day"): ResponseBuilder { const now = new Date(); this - .withHeader('Date', now.toUTCString()) - .withHeader('Last-Modified', now.toUTCString()) - .withHeader('Expires', new Date(now.getTime() + TimeString`${duration}`).toUTCString()) - .withHeader( 'max-age', (Math.round(TimeString`${duration}` / 1000)).toString()) - + .withHeader("Date", now.toUTCString()) + .withHeader("Last-Modified", now.toUTCString()) + .withHeader("Expires", new Date(now.getTime() + TimeString`${duration}`).toUTCString()) + .withHeader("max-age", (Math.round(TimeString`${duration}` / 1000)).toString()); + return this; } @@ -136,10 +136,10 @@ export class ResponseBuilder { */ public withDisabledCache(): ResponseBuilder { this - .withHeader('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT') - .withHeader('Last-Modified', new Date().toUTCString()) - .withHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); - + .withHeader("Expires", "Mon, 26 Jul 1997 05:00:00 GMT") + .withHeader("Last-Modified", new Date().toUTCString()) + .withHeader("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); + return this; } @@ -148,18 +148,18 @@ export class ResponseBuilder { */ public build(): Response { // Build our headers - const headers: ResponseHeader = {}; - for(const name of this.getHeaders().keys()) { + const headers: ResponseHeader = {}; + for (const name of this.getHeaders().keys()) { headers[name] = this.getHeaderLine(name); } - + // Return our final response return new Response( this._body, { status: this._status, headers: headers, - } + }, ); } } diff --git a/webserver/http/status-codes.ts b/webserver/http/status-codes.ts index ddbe5029..f66ea45a 100644 --- a/webserver/http/status-codes.ts +++ b/webserver/http/status-codes.ts @@ -3,7 +3,7 @@ export enum StatusCodes { SWITCHING_PROTOCOLS = 101, PROCESSING = 102, EARLY_HINTS = 103, - + OK = 200, CREATED = 201, ACCEPTED = 202, @@ -14,7 +14,7 @@ export enum StatusCodes { MULTI_STATUS = 207, ALREADY_REPORTED = 208, IM_USED = 226, - + MULTIPLE_CHOICES = 300, MOVED_PERMANENTLY = 301, FOUND = 302, @@ -24,7 +24,7 @@ export enum StatusCodes { UNUSED = 306, TEMPORARY_REDIRECT = 307, PERMANENT_REDIRECT = 308, - + BAD_REQUEST = 400, UNAUTHORIZED = 401, PAYMENT_REQUIRED = 402, @@ -54,7 +54,7 @@ export enum StatusCodes { TOO_MANY_REQUESTS = 429, REQUEST_HEADER_FIELDS_TOO_LARGE = 431, UNAVAILABLE_FOR_LEGAL_REASONS = 451, - + INTERNAL_SERVER_ERROR = 500, NOT_IMPLEMENTED = 501, BAD_GATEWAY = 502, @@ -65,5 +65,5 @@ export enum StatusCodes { INSUFFICIENT_STORAGE = 507, LOOP_DETECTED = 508, NOT_EXTENDED = 510, - NETWORK_AUTHENTICATION_REQUIRED = 511 + NETWORK_AUTHENTICATION_REQUIRED = 511, } diff --git a/webserver/pathToRegexp.ts b/webserver/pathToRegexp.ts index abeb375f..c8be6514 100644 --- a/webserver/pathToRegexp.ts +++ b/webserver/pathToRegexp.ts @@ -190,7 +190,7 @@ export function parse(str: string, options: ParseOptions = {}): Token[] { prefix, suffix: "", pattern: pattern || defaultPattern, - modifier: tryConsume("MODIFIER") || "" + modifier: tryConsume("MODIFIER") || "", }); continue; } @@ -220,7 +220,7 @@ export function parse(str: string, options: ParseOptions = {}): Token[] { pattern: name && !pattern ? defaultPattern : pattern, prefix, suffix, - modifier: tryConsume("MODIFIER") || "" + modifier: tryConsume("MODIFIER") || "", }); continue; } @@ -251,7 +251,7 @@ export interface TokensToFunctionOptions { */ export function compile

( str: string, - options?: ParseOptions & TokensToFunctionOptions + options?: ParseOptions & TokensToFunctionOptions, ) { return tokensToFunction

(parse(str, options), options); } @@ -263,18 +263,18 @@ export type PathFunction

= (data?: P) => string; */ export function tokensToFunction

( tokens: Token[], - options: TokensToFunctionOptions = {} + options: TokensToFunctionOptions = {}, ): PathFunction

{ const reFlags = flags(options); const { encode = (x: string) => x, validate = true } = options; // Compile all the tokens into regexps. - const matches = tokens.map(token => { + const matches = tokens.map((token) => { if (typeof token === "object") { return new RegExp(`^(?:${token.pattern})$`, reFlags); } }); - + // deno-lint-ignore no-explicit-any -- TODO return (data: Record | null | undefined) => { let path = ""; @@ -294,7 +294,7 @@ export function tokensToFunction

( if (Array.isArray(value)) { if (!repeat) { throw new TypeError( - `Expected "${token.name}" to not repeat, but got an array` + `Expected "${token.name}" to not repeat, but got an array`, ); } @@ -309,7 +309,7 @@ export function tokensToFunction

( if (validate && !(matches[i] as RegExp).test(segment)) { throw new TypeError( - `Expected all "${token.name}" to match "${token.pattern}", but got "${segment}"` + `Expected all "${token.name}" to match "${token.pattern}", but got "${segment}"`, ); } @@ -324,7 +324,7 @@ export function tokensToFunction

( if (validate && !(matches[i] as RegExp).test(segment)) { throw new TypeError( - `Expected "${token.name}" to match "${token.pattern}", but got "${segment}"` + `Expected "${token.name}" to match "${token.pattern}", but got "${segment}"`, ); } @@ -367,7 +367,7 @@ export type Match

= false | MatchResult

; * The match function takes a string and returns whether it matched the path. */ export type MatchFunction

= ( - path: string + path: string, ) => Match

; /** @@ -375,7 +375,7 @@ export type MatchFunction

= ( */ export function match

( str: Path, - options?: ParseOptions & TokensToRegexpOptions & RegexpToFunctionOptions + options?: ParseOptions & TokensToRegexpOptions & RegexpToFunctionOptions, ) { const keys: Key[] = []; const re = pathToRegexp(str, keys, options); @@ -388,11 +388,11 @@ export function match

( export function regexpToFunction

( re: RegExp, keys: Key[], - options: RegexpToFunctionOptions = {} + options: RegexpToFunctionOptions = {}, ): MatchFunction

{ const { decode = (x: string) => x } = options; - return function(pathname: string) { + return function (pathname: string) { const m = re.exec(pathname); if (!m) return false; @@ -406,7 +406,7 @@ export function regexpToFunction

( const key = keys[i - 1]; if (key.modifier === "*" || key.modifier === "+") { - params[key.name] = m[i].split(key.prefix + key.suffix).map(value => { + params[key.name] = m[i].split(key.prefix + key.suffix).map((value) => { return decode(value, key); }); } else { @@ -465,7 +465,7 @@ function regexpToRegexp(path: RegExp, keys?: Key[]): RegExp { prefix: "", suffix: "", modifier: "", - pattern: "" + pattern: "", }); execResult = groupsRegex.exec(path.source); } @@ -479,9 +479,9 @@ function regexpToRegexp(path: RegExp, keys?: Key[]): RegExp { function arrayToRegexp( paths: Array, keys?: Key[], - options?: TokensToRegexpOptions & ParseOptions + options?: TokensToRegexpOptions & ParseOptions, ): RegExp { - const parts = paths.map(path => pathToRegexp(path, keys, options).source); + const parts = paths.map((path) => pathToRegexp(path, keys, options).source); return new RegExp(`(?:${parts.join("|")})`, flags(options)); } @@ -491,7 +491,7 @@ function arrayToRegexp( function stringToRegexp( path: string, keys?: Key[], - options?: TokensToRegexpOptions & ParseOptions + options?: TokensToRegexpOptions & ParseOptions, ) { return tokensToRegexp(parse(path, options), keys, options); } @@ -533,13 +533,13 @@ export interface TokensToRegexpOptions { export function tokensToRegexp( tokens: Token[], keys?: Key[], - options: TokensToRegexpOptions = {} + options: TokensToRegexpOptions = {}, ) { const { strict = false, start = true, end = true, - encode = (x: string) => x + encode = (x: string) => x, } = options; const endsWith = `[${escapeString(options.endsWith || "")}]|$`; const delimiter = `[${escapeString(options.delimiter || "/#?")}]`; @@ -578,11 +578,10 @@ export function tokensToRegexp( route += !options.endsWith ? "$" : `(?=${endsWith})`; } else { const endToken = tokens[tokens.length - 1]; - const isEndDelimited = - typeof endToken === "string" - ? delimiter.indexOf(endToken[endToken.length - 1]) > -1 - : // tslint:disable-next-line - endToken === undefined; + const isEndDelimited = typeof endToken === "string" + ? delimiter.indexOf(endToken[endToken.length - 1]) > -1 + // tslint:disable-next-line + : endToken === undefined; if (!strict) { route += `(?:${delimiter}(?=${endsWith}))?`; @@ -611,7 +610,7 @@ export type Path = string | RegExp | Array; export function pathToRegexp( path: Path, keys?: Key[], - options?: TokensToRegexpOptions & ParseOptions + options?: TokensToRegexpOptions & ParseOptions, ) { if (path instanceof RegExp) return regexpToRegexp(path, keys); if (Array.isArray(path)) return arrayToRegexp(path, keys, options); diff --git a/webserver/registry/registry.ts b/webserver/registry/registry.ts index cf4a64c0..441c755d 100644 --- a/webserver/registry/registry.ts +++ b/webserver/registry/registry.ts @@ -3,11 +3,11 @@ interface RegistryItem { } export class Registry { - private static _items: RegistryItem = {}; + private static _items: RegistryItem = {}; /** * Add an item to the registry - * + * * @param name * @param module */ @@ -17,16 +17,16 @@ export class Registry { /** * Get an item from the registry - * + * * @param name */ - public static get(name: string): Module|null { + public static get(name: string): Module | null { return Registry._items[name] ?? null; } /** * Check whether the registry has an item with name - * + * * @param name */ public static has(name: string): boolean { diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index 4ed4e73e..eea312af 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -8,29 +8,33 @@ interface CacheItem { } export class Handlebars { - private static _cache: CacheItem = {}; - - public static async render(path: string, vars: ViewVariable = {}, cache = true): Promise { + private static _cache: CacheItem = {}; + + public static async render( + path: string, + vars: ViewVariable = {}, + cache = true, + ): Promise { // Read and execute from cache if possible - if(cache && path in Handlebars._cache) return Handlebars._cache[path](vars); - + if (cache && path in Handlebars._cache) return Handlebars._cache[path](vars); + // Load our template - const template = await Handlebars.getTemplate(path) ?? raise('Could not load template'); - + const template = await Handlebars.getTemplate(path) ?? raise("Could not load template"); + // Compile our template // Cache it if need be - const compiled = hbs.compile(template) ?? raise('Could not compile template'); - if(cache) Handlebars._cache[path] = compiled; + const compiled = hbs.compile(template) ?? raise("Could not compile template"); + if (cache) Handlebars._cache[path] = compiled; // Let the engine render return compiled(vars); } - + private static async getTemplate(path: string): Promise { // Make sure out template exists try { await Deno.stat(path); - } catch(e) { + } catch (e) { throw new Error(`Could not render handlebars template: Could not read template at "${path}"`, e.stack); } diff --git a/webserver/routing/route.ts b/webserver/routing/route.ts index 332ee1cc..071b665d 100644 --- a/webserver/routing/route.ts +++ b/webserver/routing/route.ts @@ -3,15 +3,23 @@ export class Route { private readonly path: string, private readonly controller: string, private readonly action: string, - private readonly method: string + private readonly method: string, ) { } - - public getPath(): typeof this.path { return this.path; } - - public getController(): typeof this.controller { return this.controller; } - - public getAction(): typeof this.action { return this.action; } - - public getMethod(): typeof this.method { return this.method; } + + public getPath(): typeof this.path { + return this.path; + } + + public getController(): typeof this.controller { + return this.controller; + } + + public getAction(): typeof this.action { + return this.action; + } + + public getMethod(): typeof this.method { + return this.method; + } } diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index c5d6112e..02bf102a 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -3,7 +3,7 @@ import { readAll } from "https://deno.land/std@0.213.0/io/read_all.ts"; import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../utility/inflector.ts"; import { Logger } from "../../core/logger.ts"; -import {QueryParameters, Request as ChompRequest, RequestParameters} from "../http/request.ts"; +import { QueryParameters, Request as ChompRequest, RequestParameters } from "../http/request.ts"; import { StatusCodes } from "../http/status-codes.ts"; import { Route as ChompRoute } from "./route.ts"; import { Controller } from "../controller/controller.ts"; @@ -20,7 +20,9 @@ interface Route { export class Router { private static readonly _controllerDir = `file://${Deno.cwd()}/src/controller`; private static routes: ChompRoute[] = []; - public static getRoutes() { return Router.routes; } + public static getRoutes() { + return Router.routes; + } /** * Match the controller and action to a route @@ -33,7 +35,7 @@ export class Router { let path = request.url .replace("http://", "") .replace("https://", ""); - if(host !== null) path = path.replace(host, ""); + if (host !== null) path = path.replace(host, ""); // Ignore query parameters path = path.split("?", 1)[0]; @@ -43,14 +45,16 @@ export class Router { // Check if it's the right path // Return the route if route found for (const route of Router.routes) { - if(route.getMethod() !== request.method) continue; + if (route.getMethod() !== request.method) continue; // Make sure we have a matching route const matches = pathToRegexp(route.getPath()).exec(path); - if(matches) return { - route: route, - path: path - }; + if (matches) { + return { + route: route, + path: path, + }; + } } } @@ -65,15 +69,15 @@ export class Router { // Make sure a route was found // Otherwise return a 404 response const route = Router.route(request); - if(!route || !route.route) { + if (!route || !route.route) { return new Response( - 'The requested page could not be found.', + "The requested page could not be found.", { status: StatusCodes.NOT_FOUND, headers: { - 'Content-Type': 'text/plain' - } - } + "Content-Type": "text/plain", + }, + }, ); } @@ -87,37 +91,39 @@ export class Router { Router.getParams(route.route, route.path), Router.getQuery(request.url), Router.getAuth(request), - clientIp + clientIp, ); // Import and cache controller file if need be - if(!Registry.has(req.getRoute().getController())) { + if (!Registry.has(req.getRoute().getController())) { try { // Import the module - const module = await import(`${Router._controllerDir}/${Inflector.lcfirst(req.getRoute().getController())}.controller.ts`); + const module = await import( + `${Router._controllerDir}/${Inflector.lcfirst(req.getRoute().getController())}.controller.ts` + ); // Make sure the controller class was found - if(!(`${req.getRoute().getController()}Controller` in module)) { + if (!(`${req.getRoute().getController()}Controller` in module)) { raise(`No class "${req.getRoute().getController()}Controller" could be found.`); } // Make sure the controller class extends our base controller - if(!(module[`${req.getRoute().getController()}Controller`].prototype instanceof Controller)) { + if (!(module[`${req.getRoute().getController()}Controller`].prototype instanceof Controller)) { raise(`Class "${req.getRoute().getController()}Controller" does not properly extend Chomp's controller.`); } // Add the module to our registry Registry.add(`${req.getRoute().getController()}Controller`, module); - } catch(e) { + } catch (e) { Logger.error(`Could not import "${req.getRoute().getController()}": ${e.message}`, e.stack); return new Response( - 'Internal Server Error', + "Internal Server Error", { status: 500, headers: { - 'content-type': 'text/plain' - } - } + "content-type": "text/plain", + }, + }, ); } } @@ -125,7 +131,8 @@ export class Router { // Run our controller try { // Instantiate the controller - const module = Registry.get(`${req.getRoute().getController()}Controller`) ?? raise(`"${req.getRoute().getController()}Controller" was not found in registry.`) + const module = Registry.get(`${req.getRoute().getController()}Controller`) ?? + raise(`"${req.getRoute().getController()}Controller" was not found in registry.`); const controller = new module[`${req.getRoute().getController()}Controller`](req); // Run the controller's initializer @@ -139,16 +146,16 @@ export class Router { // Return our response return controller.getResponse().build(); - } catch(e) { + } catch (e) { Logger.error(`Could not execute "${req.getRoute().getController()}": ${e.message}`, e.stack); return new Response( - 'An Internal Server Error Occurred', + "An Internal Server Error Occurred", { status: 500, headers: { - 'Content-Type': 'text/plain' - } - } + "Content-Type": "text/plain", + }, + }, ); } } @@ -190,7 +197,7 @@ export class Router { */ public static async getBody(request: Request): Promise { // Make sure a body is set - if(request.body === null) return ''; + if (request.body === null) return ""; // Create a reader const reader = readerFromStreamReader(request.body.getReader()); @@ -211,7 +218,7 @@ export class Router { public static getAuth(request: Request): string { // Get our authorization header // Return it or empty string if none found - return request.headers.get("authorization") ?? ''; + return request.headers.get("authorization") ?? ""; } /** @@ -222,11 +229,13 @@ export class Router { * @returns void */ public static add(route: Route): void { - Router.routes.push(new ChompRoute( - route.path, - Inflector.pascalize(route.controller), - route.action, - route.method ?? 'GET', - )); + Router.routes.push( + new ChompRoute( + route.path, + Inflector.pascalize(route.controller), + route.action, + route.method ?? "GET", + ), + ); } } diff --git a/webserver/webserver.ts b/webserver/webserver.ts index f163671e..bf66bf45 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -3,10 +3,10 @@ import { Router } from "./routing/router.ts"; import { StatusCodes } from "./http/status-codes.ts"; export class Webserver { - private server: Deno.Listener|null = null; + private server: Deno.Listener | null = null; constructor( - private readonly port: number = 80 + private readonly port: number = 80, ) { } @@ -27,25 +27,30 @@ export class Webserver { const httpConn: Deno.HttpConn = Deno.serveHttp(conn); // Handle each request for this connection - for await(const request of httpConn) { - Logger.debug(`Request from "${(conn.remoteAddr as Deno.NetAddr).hostname!}:${(conn.remoteAddr as Deno.NetAddr).port!}": ${request.request.method} | ${request.request.url}`); + for await (const request of httpConn) { + Logger.debug( + `Request from "${(conn.remoteAddr as Deno.NetAddr).hostname!}:${(conn.remoteAddr as Deno.NetAddr) + .port!}": ${request.request.method} | ${request.request.url}`, + ); try { // Run the required route const response: Response = await Router.execute(request.request, (conn.remoteAddr as Deno.NetAddr).hostname!); // Send our response await request.respondWith(response); - } catch(e) { + } catch (e) { Logger.error(`Could not serve response: ${e.message}`, e.stack); - await request.respondWith(new Response( - 'An Internal Server Error Occurred', - { - status: StatusCodes.INTERNAL_SERVER_ERROR, - headers: { - 'Content-Type': 'text/plain' - } - } - )); + await request.respondWith( + new Response( + "An Internal Server Error Occurred", + { + status: StatusCodes.INTERNAL_SERVER_ERROR, + headers: { + "Content-Type": "text/plain", + }, + }, + ), + ); } } } diff --git a/websocket/authenticator.ts b/websocket/authenticator.ts index b0b8d9e3..4f8fdb31 100644 --- a/websocket/authenticator.ts +++ b/websocket/authenticator.ts @@ -7,11 +7,11 @@ export class Authenticator { * * @param token */ - public static client(token: string = ''): boolean { - if(!token) { + public static client(token: string = ""): boolean { + if (!token) { Logger.debug(`No token has been set! (this may be a bug)`); return false; } - return token === Configure.get('websocket_client_auth', ''); + return token === Configure.get("websocket_client_auth", ""); } } diff --git a/websocket/events.ts b/websocket/events.ts index 034bd3d0..a91c4a6a 100644 --- a/websocket/events.ts +++ b/websocket/events.ts @@ -9,7 +9,9 @@ export class Events { private static list: IEvent[] = []; // deno-lint-ignore no-explicit-any -- TODO private static handlers: any = {}; - public static getEvents() { return Events.list; } + public static getEvents() { + return Events.list; + } public static getHandler(name: string) { return Events.list.find((event: IEvent) => event.name === name); @@ -18,8 +20,8 @@ export class Events { public static async add(event: IEvent) { try { // Import the event handler - Events.handlers[event.handler] = await import(`file://${Deno.cwd()}/src/events/${event.handler}.ts`) - } catch(e) { + Events.handlers[event.handler] = await import(`file://${Deno.cwd()}/src/events/${event.handler}.ts`); + } catch (e) { Logger.error(`Could not register event handler for "${event}": ${e.message}`, e.stack); return; } @@ -31,15 +33,15 @@ export class Events { public static async dispatch(event: string, data: any = {}) { // Get the event handler const handler = Events.getHandler(event); - if(!handler) return Logger.warning(`Event "${event}" does not exist! (did you register it?`); + if (!handler) return Logger.warning(`Event "${event}" does not exist! (did you register it?`); // Create an instance of the event handler const controller = new Events.handlers[handler.handler][`${event}Event`](data); // Execute the handler's execute method try { - await controller['execute'](data); - } catch(e) { + await controller["execute"](data); + } catch (e) { Logger.error(`Could not dispatch event "${event}": "${e.message}"`, e.stack); } } diff --git a/websocket/websocket.ts b/websocket/websocket.ts index 8f12cd5c..393ecb09 100644 --- a/websocket/websocket.ts +++ b/websocket/websocket.ts @@ -1,4 +1,4 @@ -import { WebSocketServer, WebSocketAcceptedClient } from "https://deno.land/x/websocket@v0.1.3/mod.ts"; +import { WebSocketAcceptedClient, WebSocketServer } from "https://deno.land/x/websocket@v0.1.3/mod.ts"; import { Logger } from "../core/logger.ts"; import { Events } from "./events.ts"; import { Authenticator } from "./authenticator.ts"; @@ -7,7 +7,7 @@ import { Configure } from "../core/configure.ts"; export class Websocket { private readonly port: number = 80; private readonly authenticate: boolean = false; - private server: WebSocketServer|null = null; + private server: WebSocketServer | null = null; constructor(port: number = 80, authenticate: boolean = false) { this.port = port; @@ -15,19 +15,21 @@ export class Websocket { } public start() { - this.server = new WebSocketServer(this.port, Configure.get('real_ip_header', 'X-Forwarded-For') ?? null); + this.server = new WebSocketServer(this.port, Configure.get("real_ip_header", "X-Forwarded-For") ?? null); this.server.on("connection", (client: WebSocketAcceptedClient, url: string) => { Logger.info(`New WebSocket connection from "${(client.webSocket.conn.remoteAddr as Deno.NetAddr).hostname!}"...`); // Authenticate if required - if(this.authenticate === true && !Authenticator.client(url.replace('/', ''))) { - Logger.warning(`Closing connection with "${(client.webSocket.conn.remoteAddr as Deno.NetAddr).hostname!}": Invalid token!`); - client.close(1000, 'Invalid authentication token!'); + if (this.authenticate === true && !Authenticator.client(url.replace("/", ""))) { + Logger.warning( + `Closing connection with "${(client.webSocket.conn.remoteAddr as Deno.NetAddr).hostname!}": Invalid token!`, + ); + client.close(1000, "Invalid authentication token!"); return; } // Dispatch "ClientConnect" event - this.handleEvent('ClientConnect', {client: client}); + this.handleEvent("ClientConnect", { client: client }); client.on("message", (message: string) => this.onMessage(message)); }); @@ -36,24 +38,24 @@ export class Websocket { // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public broadcast(eventString: string, data: any) { // Make sure the server has started - if(!this.server) return; + if (!this.server) return; // Loop over each client // Check whether they are still alive // Send the event to the clients that are still alive - for(const client of this.server.clients) { - if(!client) continue; - if(client.isClosed) continue; + for (const client of this.server.clients) { + if (!client) continue; + if (client.isClosed) continue; client.send(JSON.stringify({ event: eventString, - data: data + data: data, })); } } private async onMessage(message: string) { // Check if a message was set - if(!message) return; + if (!message) return; // Decode the message const data = JSON.parse(message); @@ -61,16 +63,16 @@ export class Websocket { // Get the Event let event = data.event; const tokens = []; - for(let token of event.split('_')) { + for (let token of event.split("_")) { token = token.toLowerCase(); token = token[0].toUpperCase() + token.slice(1); tokens.push(token); } - event = tokens.join(''); + event = tokens.join(""); try { await this.handleEvent(event, data.data); - } catch(e) { + } catch (e) { Logger.error(e.message); } } @@ -78,7 +80,7 @@ export class Websocket { // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used private async handleEvent(event: string, data: any = {}) { const handler = Events.getHandler(event); - if(!handler) return Logger.warning(`Event "${event}" does not exists! (did you register it?)`); + if (!handler) return Logger.warning(`Event "${event}" does not exists! (did you register it?)`); // Import the event handler const imported = await import(`file://${Deno.cwd()}/src/events/${handler.handler}.ts`); @@ -88,8 +90,8 @@ export class Websocket { // Execute the event handler's execute method try { - await controller['execute'](data); - } catch(e) { + await controller["execute"](data); + } catch (e) { Logger.error(`Could not dispatch event "${event}": "${e.message}"`, e.stack); } } From 86d40cc206d1178e0968e64d5830fd0d62cb9f1e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 18:08:30 +0200 Subject: [PATCH 226/379] Fix small test error --- core/logger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/logger.ts b/core/logger.ts index 9e945d1f..84ded6ff 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -54,9 +54,9 @@ export class Logger { * @param level {LogLevels} * @param handler {any} */ - // @ts-ignore TODO: Figure out how to replace Function with something more sane - // deno-lint-ignore ban-types -- TODO public static setHandler(level: LogLevels, handler: Function): void { + // @ts-ignore TODO: Figure out how to replace Function with something more sane + // deno-lint-ignore ban-types -- TODO Logger._handlers[level] = handler; } From eff62428709764d00d4c60d696efdef3dca76229 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 18:34:10 +0200 Subject: [PATCH 227/379] Attempt number 2 --- core/logger.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/logger.ts b/core/logger.ts index 84ded6ff..ea774c8e 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -54,9 +54,8 @@ export class Logger { * @param level {LogLevels} * @param handler {any} */ - public static setHandler(level: LogLevels, handler: Function): void { + public static setHandler(level: LogLevels, handler: typeof Handlers): void { // @ts-ignore TODO: Figure out how to replace Function with something more sane - // deno-lint-ignore ban-types -- TODO Logger._handlers[level] = handler; } From a3acdcec1dcd8daa8f915e935603f558c750b47d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 18:43:21 +0200 Subject: [PATCH 228/379] *sigh* --- core/logger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/logger.ts b/core/logger.ts index ea774c8e..8c5bdf52 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -54,8 +54,8 @@ export class Logger { * @param level {LogLevels} * @param handler {any} */ - public static setHandler(level: LogLevels, handler: typeof Handlers): void { - // @ts-ignore TODO: Figure out how to replace Function with something more sane + // @ts-ignore TODO: Figure out how to replace any type with something more sane + public static setHandler(level: LogLevels, handler: any): void { Logger._handlers[level] = handler; } From ab64c596a6d04ca499b797da61b5f3dad51ce9f2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 18:44:08 +0200 Subject: [PATCH 229/379] *sigh^2* --- core/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/logger.ts b/core/logger.ts index 8c5bdf52..8f9bbedd 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -54,7 +54,7 @@ export class Logger { * @param level {LogLevels} * @param handler {any} */ - // @ts-ignore TODO: Figure out how to replace any type with something more sane + // deno-lint-ignore no-explicit-any -- TODO: Figure out how to replace any type with something more sane public static setHandler(level: LogLevels, handler: any): void { Logger._handlers[level] = handler; } From f879ea9a2a250d75e8a4133b5411226586aa46a3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 18:57:56 +0200 Subject: [PATCH 230/379] Update workflow --- .github/workflows/test.yml | 39 ++++++++++++-------------------------- .gitignore | 4 ++++ deno.json | 7 ++++++- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fba66710..a6466bb4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,7 +5,7 @@ on: pull_request: branches: [main] jobs: - lint: + chomp: runs-on: ubuntu-latest steps: - name: Clone repository @@ -16,31 +16,16 @@ jobs: uses: denoland/setup-deno@v1 with: deno-version: "1.40.0" - - name: Lint + - name: Check format + run: deno task test:fmt + - name: Check lint run: deno lint - test: - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v3 - with: - submodules: true - - name: Set up Deno - uses: denoland/setup-deno@v1 + - name: Run tests generating coverage + run: deno task test:coverage + - name: Generate lcov report + run: deno task coverage > cov.lcov + - name: upload coverage + uses: codecov/codecov-action@v4 with: - deno-version: "1.40.0" - - name: Run tests - run: deno test --allow-read - fmt: - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v3 - with: - submodules: true - - name: Set up Deno - uses: denoland/setup-deno@v1 - with: - deno-version: "1.40.0" - - name: Run tests - run: deno fmt --check + files: ./cov.lcov + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 27b77b5c..25505de0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ # Ignore IDE-specific folders /.idea + +# Ignore reports +/coverage +/cov.lcov diff --git a/deno.json b/deno.json index 7f383412..54fb79bc 100644 --- a/deno.json +++ b/deno.json @@ -5,12 +5,17 @@ "semiColons": true, "indentWidth": 2, "lineWidth": 120, - "exclude": [".github", ".idea", "docs"] + "exclude": [".github", ".idea", "docs", "README.md"] }, "lint": { "exclude": [".github", ".idea", "docs"], "rules": { "exclude": ["no-inferrable-types"] } + }, + "tasks": { + "coverage": "deno coverage --lcov ./cov", + "test": "deno test --allow-read", + "test:coverage": "deno test --coverage=./cov --allow-read" } } From 1dc9863aeea4fab28a74862bb8ed8105d92220f3 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 18 Sep 2024 18:59:16 +0200 Subject: [PATCH 231/379] Fix error --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a6466bb4..ad2e2691 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: with: deno-version: "1.40.0" - name: Check format - run: deno task test:fmt + run: deno fmt --check - name: Check lint run: deno lint - name: Run tests generating coverage From 4d7564cf8d7dabbaf5ad662981b0a79e7357acb5 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 21 Sep 2024 23:58:27 +0200 Subject: [PATCH 232/379] Add new utility for "contracts" --- mod.ts | 2 ++ tests/util/contract.test.ts | 22 +++++++++++++++ tests/util/name-of.test.ts | 8 ++++++ utility/contract.ts | 55 +++++++++++++++++++++++++++++++++++++ utility/name-of.ts | 16 +++++++++++ 5 files changed, 103 insertions(+) create mode 100644 tests/util/contract.test.ts create mode 100644 tests/util/name-of.test.ts create mode 100644 utility/contract.ts create mode 100644 utility/name-of.ts diff --git a/mod.ts b/mod.ts index 0af33b75..fd7a0411 100644 --- a/mod.ts +++ b/mod.ts @@ -46,9 +46,11 @@ export type { DEFAULT_OPTS, PASSWORD_DEFAULT, PasswordOptions } from "./security * Utility */ export { CheckSource } from "./utility/check-source.ts"; +export { Contract } from "./utility/contract.ts"; export { Cron } from "./utility/cron.ts"; export { empty } from "./utility/empty.ts"; export { Inflector } from "./utility/inflector.ts"; +export { nameOf } from "./utility/name-of.ts"; export { Text } from "./utility/text.ts"; export { Time } from "./utility/time.ts"; export { TimeString, TimeStringSeconds } from "./utility/time-string.ts"; diff --git a/tests/util/contract.test.ts b/tests/util/contract.test.ts new file mode 100644 index 00000000..2234c6a4 --- /dev/null +++ b/tests/util/contract.test.ts @@ -0,0 +1,22 @@ +import { Contract } from "../../utility/contract.ts"; +import { nameOf } from "../../utility/name-of.ts"; +import { assert, assertThrows } from "https://deno.land/std@0.152.0/testing/asserts.ts"; + +Deno.test("Contract Test", async (t) => { + + await t.step("require", () => { + // Test when the condition is false + assertThrows(() => Contract.require(false, "Condition must be true")); + + // Test when the condition if true + assert(() => Contract.require(true, "Condition must be true")); + }); + + await t.step("requireNotNull", () => { + // Test when the argument is null + assertThrows(() => Contract.requireNotNull(null, "testArgument")); + + // Test when the argument is not null + assert(() => Contract.requireNotNull("blabla", "testArgument")) + }); +}); diff --git a/tests/util/name-of.test.ts b/tests/util/name-of.test.ts new file mode 100644 index 00000000..426d7284 --- /dev/null +++ b/tests/util/name-of.test.ts @@ -0,0 +1,8 @@ +import { assertEquals, assertNotEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; +import {nameOf} from "../../utility/name-of.ts"; + +Deno.test("nameOf Test", async (t) => { + const testArgument = "blabla"; + assertEquals(nameOf({ testArgument }), "testArgument"); + assertNotEquals(nameOf({ testArgument }), "testargument"); +}); diff --git a/utility/contract.ts b/utility/contract.ts new file mode 100644 index 00000000..dcd743b0 --- /dev/null +++ b/utility/contract.ts @@ -0,0 +1,55 @@ +import { raise } from "../error/raise.ts"; + +/** + * Class to more easily throw errors while creating (among others) constructors. + * Allows code to be more concise and users to more easily read what it does. + * + * It was based on the .NET 6 feature of the same name. + * + */ +export class Contract { + + /** + * Make sure the condition is true, otherwise throw an error + * + * @example Basic Usage + * ```ts + * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; + * + * const myStatement = false; + * Contract.require(myStatement, "Statement must be true"); + * ``` + * + * @param condition + * @param message + */ + public static require(condition: boolean, message: string): void { + if(!condition) raise(message, "Argument"); + } + + /** + * + * @example Basic Usage + * ```ts + * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; + * + * const myArgument = "blabla"; + * Contract.requireNotNull(myArgument, "myArgument"); + * ``` + * + * @example Using the {@linkcode nameOf} utility + * ```ts + * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; + * import { nameOf } from "https://deno.land/x/chomp/utility/name-of.ts"; + * + * const myArgument = "blabla"; + * Contract.requireNotNull(myArgument, nameOf({ myArgument })); + * ``` + * + * @param argument + * @param argumentName + */ + public static requireNotNull(argument: any, argumentName: string): void { + if(argument === null) raise(`${argumentName} may not be null`, "ArgumentNull"); + } +} diff --git a/utility/name-of.ts b/utility/name-of.ts new file mode 100644 index 00000000..912c0652 --- /dev/null +++ b/utility/name-of.ts @@ -0,0 +1,16 @@ +/** + * Get the name of a passes argument + * + * TODO: Give this a cleaner API + * + * @example + * ```ts + * import { nameOf } from "https://deno.land/x/chomp/utility/name-of.ts"; + * + * const myArgument = true; + * const name = nameOf({ myArgument }); + * ``` + * + * @param variable + */ +export const nameOf = (variable: Record) => Object.keys(variable)[0] From c3c2fa735360c70ce20cc4d8b567e95ec63dce93 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 22 Sep 2024 00:02:19 +0200 Subject: [PATCH 233/379] Split up in seperate jobs so they one error doesn't cause others to fail --- .github/workflows/test.yml | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ad2e2691..0eaed6e1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,7 +5,7 @@ on: pull_request: branches: [main] jobs: - chomp: + chomp-format: runs-on: ubuntu-latest steps: - name: Clone repository @@ -18,8 +18,30 @@ jobs: deno-version: "1.40.0" - name: Check format run: deno fmt --check + chomp-lint: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v3 + with: + submodules: true + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: "1.40.0" - name: Check lint run: deno lint + chomp-tests: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v3 + with: + submodules: true + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: "1.40.0" - name: Run tests generating coverage run: deno task test:coverage - name: Generate lcov report From 47d80e3fd2deb44a4dad7be3230f33428a8b2d93 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 22 Sep 2024 00:04:39 +0200 Subject: [PATCH 234/379] Fix some errors --- tests/util/contract.test.ts | 4 +--- tests/util/name-of.test.ts | 4 ++-- utility/contract.ts | 9 +++------ utility/name-of.ts | 2 +- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/tests/util/contract.test.ts b/tests/util/contract.test.ts index 2234c6a4..8ee68320 100644 --- a/tests/util/contract.test.ts +++ b/tests/util/contract.test.ts @@ -1,9 +1,7 @@ import { Contract } from "../../utility/contract.ts"; -import { nameOf } from "../../utility/name-of.ts"; import { assert, assertThrows } from "https://deno.land/std@0.152.0/testing/asserts.ts"; Deno.test("Contract Test", async (t) => { - await t.step("require", () => { // Test when the condition is false assertThrows(() => Contract.require(false, "Condition must be true")); @@ -17,6 +15,6 @@ Deno.test("Contract Test", async (t) => { assertThrows(() => Contract.requireNotNull(null, "testArgument")); // Test when the argument is not null - assert(() => Contract.requireNotNull("blabla", "testArgument")) + assert(() => Contract.requireNotNull("blabla", "testArgument")); }); }); diff --git a/tests/util/name-of.test.ts b/tests/util/name-of.test.ts index 426d7284..38995d1a 100644 --- a/tests/util/name-of.test.ts +++ b/tests/util/name-of.test.ts @@ -1,7 +1,7 @@ import { assertEquals, assertNotEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import {nameOf} from "../../utility/name-of.ts"; +import { nameOf } from "../../utility/name-of.ts"; -Deno.test("nameOf Test", async (t) => { +Deno.test("nameOf Test", () => { const testArgument = "blabla"; assertEquals(nameOf({ testArgument }), "testArgument"); assertNotEquals(nameOf({ testArgument }), "testargument"); diff --git a/utility/contract.ts b/utility/contract.ts index dcd743b0..3b02ea67 100644 --- a/utility/contract.ts +++ b/utility/contract.ts @@ -5,10 +5,8 @@ import { raise } from "../error/raise.ts"; * Allows code to be more concise and users to more easily read what it does. * * It was based on the .NET 6 feature of the same name. - * */ export class Contract { - /** * Make sure the condition is true, otherwise throw an error * @@ -24,11 +22,10 @@ export class Contract { * @param message */ public static require(condition: boolean, message: string): void { - if(!condition) raise(message, "Argument"); + if (!condition) raise(message, "Argument"); } /** - * * @example Basic Usage * ```ts * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; @@ -49,7 +46,7 @@ export class Contract { * @param argument * @param argumentName */ - public static requireNotNull(argument: any, argumentName: string): void { - if(argument === null) raise(`${argumentName} may not be null`, "ArgumentNull"); + public static requireNotNull(argument: unknown, argumentName: string): void { + if (argument === null) raise(`${argumentName} may not be null`, "ArgumentNull"); } } diff --git a/utility/name-of.ts b/utility/name-of.ts index 912c0652..fd6388a2 100644 --- a/utility/name-of.ts +++ b/utility/name-of.ts @@ -13,4 +13,4 @@ * * @param variable */ -export const nameOf = (variable: Record) => Object.keys(variable)[0] +export const nameOf = (variable: Record) => Object.keys(variable)[0]; From 7ff66b15d24820a2c476c8c1573dbf29b19cda37 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 10 Nov 2024 02:52:10 +0100 Subject: [PATCH 235/379] Add never types --- utility/contract.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utility/contract.ts b/utility/contract.ts index 3b02ea67..529b4658 100644 --- a/utility/contract.ts +++ b/utility/contract.ts @@ -21,7 +21,7 @@ export class Contract { * @param condition * @param message */ - public static require(condition: boolean, message: string): void { + public static require(condition: boolean, message: string): void|never { if (!condition) raise(message, "Argument"); } @@ -46,7 +46,7 @@ export class Contract { * @param argument * @param argumentName */ - public static requireNotNull(argument: unknown, argumentName: string): void { + public static requireNotNull(argument: unknown, argumentName: string): void|never { if (argument === null) raise(`${argumentName} may not be null`, "ArgumentNull"); } } From 70ddae278fd84533747e2f7afe7f43b2a4fecc00 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 10 Nov 2024 02:52:23 +0100 Subject: [PATCH 236/379] Add experimental read-through cache --- core/cache.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/core/cache.ts b/core/cache.ts index fe56f8f3..afc30c33 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -148,6 +148,39 @@ export class Cache { Cache._items.delete(key); } + /** + * Read-through cache. + * + * Will check if the cache item can be obtained and if not, will execute the callable function. + * The result will then be stored in the cache. + * + * **NOTE:** This feature is currently experimental. + * + * TODO: Test whether it actually works as intended + * + * @example Basic Usage + * ```ts + * const res = Cache.remember('cache item name, "+1 minute", async function { return true }); + * ``` + * + * @param key + * @param expiry + * @param callable + */ + public static async remember(key: string, expiry: string | null = "+1 minute", callable: Promise): Promise { + // Check if cache item exists and hasn't expired + if(!Cache.expired(key)) return Cache.get(key); + + // Cache does not exist, run callable + const res = await callable(); + + // Add result to cache + Cache.set(key, res, expiry); + + // Return result + return res; + } + /** * Dumps the raw cache contents. * Should only be used for debugging purposes. From 58cf23b1871e75478c297169eab643c9bedbd138 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 16 Nov 2024 08:28:45 +0100 Subject: [PATCH 237/379] Add Cache metrics --- core/cache.ts | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index afc30c33..026e04ef 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -7,8 +7,42 @@ interface CacheItem { expires: Date | null; } +interface CacheMetrics { + hit: number; + miss: number; +} + export class Cache { private static _items: Map = new Map(); + private static _metrics: CacheMetrics = { hit: 0, miss: 0 }; + + /** + * Get the metrics for the cache + * + * @example Basic usage + * ```ts + * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; + * const metrics = Cache.metrics(); + * const hits = Cache.metrics("hit"); + * const misses = Cache.metrics("miss"); + * const rate = Cache.metrics("rate"); + * ``` + * + * @param key + */ + public static metrics(key: keyof CacheMetrics|"rate"|null = null): number|CacheMetrics { + switch(key) { + case "hit": + return Cache._metrics.hit; + case "miss": + return Cache._metrics.miss; + case "rate": + const percentile = Cache._metrics.hit / (Cache._metrics.hit + Cache._metrics.miss); + return Math.round(percentile * 100) / 100; + default: + return Cache._metrics; + } + } /** * Add an item to the cache. @@ -60,12 +94,19 @@ export class Cache { */ public static get(key: string, optimistic = false): unknown | null { // Return null if the item doesn't exist - if (!Cache.exists(key)) return null; + if (!Cache.exists(key)) { + Cache._metrics.miss++; + return null; + } // Return null if the item expired - if (Cache.expired(key) && !optimistic) return null; + if (Cache.expired(key) && !optimistic) { + Cache._metrics.miss++; + return null; + } // Return the item's data + Cache._metrics.hit++; return Cache._items.get(key)?.data; } From df189d4c802ee2958ab156712c70e2e53f060282 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 16 Nov 2024 13:32:19 +0100 Subject: [PATCH 238/379] Fix errors --- communication/ntfy.ts | 2 +- webserver/http/response-builder.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/communication/ntfy.ts b/communication/ntfy.ts index 5a6c55c8..85e75dc6 100644 --- a/communication/ntfy.ts +++ b/communication/ntfy.ts @@ -1,4 +1,4 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; export class Ntfy { public constructor( diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts index 883c12cd..ca1fed46 100644 --- a/webserver/http/response-builder.ts +++ b/webserver/http/response-builder.ts @@ -1,5 +1,5 @@ import { StatusCodes } from "./status-codes.ts"; -import { T as TimeString } from "../../utility/time-string.ts"; +import { TimeString } from "../../utility/time-string.ts"; interface ResponseHeader { [key: string]: string; From ad596a0c2c434e1e4c2924dee6353d612d2cce14 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 16 Nov 2024 13:45:57 +0100 Subject: [PATCH 239/379] Create metrics entry for total --- core/cache.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index 026e04ef..e231ef02 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -30,14 +30,16 @@ export class Cache { * * @param key */ - public static metrics(key: keyof CacheMetrics|"rate"|null = null): number|CacheMetrics { + public static metrics(key: keyof CacheMetrics|"rate"|"total"|null = null): number|CacheMetrics { switch(key) { case "hit": return Cache._metrics.hit; case "miss": return Cache._metrics.miss; + case "total": + return Cache._metrics.hit + Cache._metrics.miss; case "rate": - const percentile = Cache._metrics.hit / (Cache._metrics.hit + Cache._metrics.miss); + const percentile = Cache._metrics.hit / Cache.metrics("total"); return Math.round(percentile * 100) / 100; default: return Cache._metrics; From b31a7578ca4eacbbd7243dafead0887ff0e82e23 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 16 Nov 2024 13:50:48 +0100 Subject: [PATCH 240/379] Fix bug and add note --- core/cache.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/cache.ts b/core/cache.ts index e231ef02..b0ba9c83 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -19,6 +19,8 @@ export class Cache { /** * Get the metrics for the cache * + * **NOTE:** Rate will be returned 0-1 + * * @example Basic usage * ```ts * import { Cache } from "https://deno.land/x/chomp/core/cache.ts"; @@ -40,7 +42,8 @@ export class Cache { return Cache._metrics.hit + Cache._metrics.miss; case "rate": const percentile = Cache._metrics.hit / Cache.metrics("total"); - return Math.round(percentile * 100) / 100; + if(percentile > 0) return Math.round(percentile * 100) / 100; + return 0; default: return Cache._metrics; } From 409dd95bfdf0fe9de438652374d3ebb7d9355c35 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 16 Nov 2024 14:14:06 +0100 Subject: [PATCH 241/379] Add byte-formatting utility --- mod.ts | 1 + utility/format-bytes.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 utility/format-bytes.ts diff --git a/mod.ts b/mod.ts index fd7a0411..c0a32f38 100644 --- a/mod.ts +++ b/mod.ts @@ -49,6 +49,7 @@ export { CheckSource } from "./utility/check-source.ts"; export { Contract } from "./utility/contract.ts"; export { Cron } from "./utility/cron.ts"; export { empty } from "./utility/empty.ts"; +export { formatBytes } from "./utility/format-bytes.ts"; export { Inflector } from "./utility/inflector.ts"; export { nameOf } from "./utility/name-of.ts"; export { Text } from "./utility/text.ts"; diff --git a/utility/format-bytes.ts b/utility/format-bytes.ts new file mode 100644 index 00000000..1c7ca36c --- /dev/null +++ b/utility/format-bytes.ts @@ -0,0 +1,27 @@ +const defaultSizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; + +/** + * Format bytes to a string + * + * @example Basic usage + * ```ts + * import { formatBytes } from "https://deno.land/x/chomp/utility/format-bytes.ts" + * const size = formatBytes(1024); + * ``` + * + * @source https://stackoverflow.com/a/18650828/5001849 + * + * @param bytes + * @param decimals + * @param sizes Array of sizes + * @param si Set to false to use IEC prefixes (1024 instead of 1000) + */ +export function formatBytes(bytes: number, decimals: number = 2, sizes: string[] = defaultSizes, si: boolean = false): string { + if (!+bytes) return '0 Bytes' + + const k: number = si ? 1000 : 1024; + const dm: number = decimals < 0 ? 0 : decimals + const i: number = Math.floor(Math.log(bytes) / Math.log(k)) + + return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}` +} From 648e396754a9cac57d2dd6b46870c937ebf93786 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 16 Nov 2024 15:55:26 +0100 Subject: [PATCH 242/379] Keep track of writes and swept entries as well --- core/cache.ts | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index b0ba9c83..3d54071f 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -8,13 +8,24 @@ interface CacheItem { } interface CacheMetrics { - hit: number; - miss: number; + reads: { + hit: number; + miss: number; + }; + writes: number; + swept: number; } export class Cache { private static _items: Map = new Map(); - private static _metrics: CacheMetrics = { hit: 0, miss: 0 }; + private static _metrics: CacheMetrics = { + reads: { + hit: 0, + miss: 0 + }, + writes: 0, + swept: 0, + }; /** * Get the metrics for the cache @@ -28,22 +39,28 @@ export class Cache { * const hits = Cache.metrics("hit"); * const misses = Cache.metrics("miss"); * const rate = Cache.metrics("rate"); + * const writes = Cache.metrics("writes"); + * const swept = Cache.metrics("swept"); * ``` * * @param key */ - public static metrics(key: keyof CacheMetrics|"rate"|"total"|null = null): number|CacheMetrics { + public static metrics(key: keyof CacheMetrics["reads"]|"rate"|"total"|"writes"|"swept"|null = null): number|CacheMetrics { switch(key) { case "hit": - return Cache._metrics.hit; + return Cache._metrics.reads.hit; case "miss": - return Cache._metrics.miss; + return Cache._metrics.reads.miss; case "total": - return Cache._metrics.hit + Cache._metrics.miss; + return Cache._metrics.reads.hit + Cache._metrics.reads.miss; case "rate": - const percentile = Cache._metrics.hit / Cache.metrics("total"); + const percentile = Cache._metrics.reads.hit / Cache.metrics("total"); if(percentile > 0) return Math.round(percentile * 100) / 100; return 0; + case "writes": + return Cache._metrics.writes; + case "swept": + return Cache._metrics.swept; default: return Cache._metrics; } @@ -100,18 +117,18 @@ export class Cache { public static get(key: string, optimistic = false): unknown | null { // Return null if the item doesn't exist if (!Cache.exists(key)) { - Cache._metrics.miss++; + Cache._metrics.reads.miss++; return null; } // Return null if the item expired if (Cache.expired(key) && !optimistic) { - Cache._metrics.miss++; + Cache._metrics.reads.miss++; return null; } // Return the item's data - Cache._metrics.hit++; + Cache._metrics.reads.hit++; return Cache._items.get(key)?.data; } @@ -284,6 +301,7 @@ export class Cache { // Clean up items that have expired Logger.debug(`Removing expired cache item "${key}"`); Cache._items.delete(key); + Cache._metrics.swept++; } } } From 88074daeabf4bdea3786375be5d56f0766eed653 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 16 Nov 2024 15:58:59 +0100 Subject: [PATCH 243/379] Actually increase counter for writes --- core/cache.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/cache.ts b/core/cache.ts index 3d54071f..b6c04025 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -92,6 +92,7 @@ export class Cache { data: value, expires: expiresAt, }); + Cache._metrics.writes++; } /** From da23f5edf8584b3fba9e57b9c598f8fa0dd1a8c4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 16 Nov 2024 18:01:32 +0100 Subject: [PATCH 244/379] Increase counter on miss for Cache.remember --- core/cache.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/cache.ts b/core/cache.ts index b6c04025..eb54dfbc 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -234,6 +234,7 @@ export class Cache { public static async remember(key: string, expiry: string | null = "+1 minute", callable: Promise): Promise { // Check if cache item exists and hasn't expired if(!Cache.expired(key)) return Cache.get(key); + Cache._metrics.reads.miss++; // Cache does not exist, run callable const res = await callable(); From 2444db59999aa217ae5dd5efac8845c33bc2c919 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 16 Nov 2024 18:18:07 +0100 Subject: [PATCH 245/379] Fix some errors and change percentage calculation --- core/cache.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index eb54dfbc..c2dcb75b 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -53,10 +53,11 @@ export class Cache { return Cache._metrics.reads.miss; case "total": return Cache._metrics.reads.hit + Cache._metrics.reads.miss; - case "rate": - const percentile = Cache._metrics.reads.hit / Cache.metrics("total"); - if(percentile > 0) return Math.round(percentile * 100) / 100; + case "rate": { + const percentile = +(Cache._metrics.reads.hit / Cache.metrics("total")).toFixed(4); + if(percentile > 0) return percentile; return 0; + } case "writes": return Cache._metrics.writes; case "swept": From 9a466471d219a6757e7b3444526de7bb5df10027 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 22 Nov 2024 03:21:15 +0100 Subject: [PATCH 246/379] Allow getting size of cache --- core/cache.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/cache.ts b/core/cache.ts index c2dcb75b..a57a60f2 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -45,7 +45,7 @@ export class Cache { * * @param key */ - public static metrics(key: keyof CacheMetrics["reads"]|"rate"|"total"|"writes"|"swept"|null = null): number|CacheMetrics { + public static metrics(key: keyof CacheMetrics["reads"]|"rate"|"total"|"writes"|"swept"|"size"|null = null): number|CacheMetrics { switch(key) { case "hit": return Cache._metrics.reads.hit; @@ -62,6 +62,8 @@ export class Cache { return Cache._metrics.writes; case "swept": return Cache._metrics.swept; + case "size": + return Cache._items.size; default: return Cache._metrics; } From 42648aece93a7a134c054970c783eea770ac545f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 24 Nov 2024 23:27:19 +0100 Subject: [PATCH 247/379] Add finder method --- communication/couchdb.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 812ebf8c..e59cb8b5 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -253,6 +253,41 @@ export class CouchDB { return await this.raw(`_partition/${partition}/_design/${design}/_view/${view}`); } + /** + * Find a document + * + * @example Basic usage + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(...); + * const resp = await couchdb.find({"_id": "example}); + * ``` + * + * @example Specific fields only + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(...); + * const resp = await couchdb.find({"_id": "example}, ["_id", "_rev", "example_field"]); + * ``` + * + * @param selector + * @param fields + */ + public async find(selector: any, fields: string[]|null = null): Promise { + // Instantiate body with selector + const body = { + selector: selector, + }; + + // Check if we want only specific fields + if(fields !== null) body.fields = fields; + + // Execute query + return this.raw(`_find`, body, {method: 'POST'}); + } + /** * Main request handler. * This method is used for most of our other methods as well. From 1a2eda8f0566b8c4b3f34a1ee1243a0a6228619d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 27 Nov 2024 22:19:16 +0100 Subject: [PATCH 248/379] Export CouchOverrides --- communication/couchdb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index e59cb8b5..2eea2231 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -14,7 +14,7 @@ export interface CouchResponse { }; } -interface CouchOverrides { +export interface CouchOverrides { method?: string; } From 2c300008e79bd4da6cacacc5faef785cd0e7f574 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 7 Dec 2024 16:24:22 +0100 Subject: [PATCH 249/379] Make linter happier (might break stuff) --- communication/couchdb.ts | 11 +++++++++-- communication/graphql.ts | 2 ++ communication/influxdb.ts | 16 +++++++--------- communication/nut.ts | 10 +++++----- core/cache.ts | 7 +++++-- security/hash.ts | 2 +- utility/empty.ts | 2 +- webserver/controller/controller.ts | 12 +++++++++--- webserver/http/response-builder.ts | 4 ++-- webserver/registry/registry.ts | 6 +++--- webserver/renderers/handlebars.ts | 2 ++ webserver/routing/router.ts | 4 ++++ 12 files changed, 50 insertions(+), 28 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 2eea2231..b9355d29 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -3,6 +3,13 @@ interface Auth { password: string; } + +interface CouchRequest { + method: string; + headers: any; + body?: string; +} + export interface CouchResponse { status: number; statusText: string; @@ -277,7 +284,7 @@ export class CouchDB { */ public async find(selector: any, fields: string[]|null = null): Promise { // Instantiate body with selector - const body = { + const body: {selector: any, fields?:string[]} = { selector: selector, }; @@ -304,7 +311,7 @@ export class CouchDB { // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public async raw(endpoint: string, body: any = null, overrides: CouchOverrides = {}): Promise { // Start building opts - const opts = { + const opts: CouchRequest = { method: overrides["method"] ? overrides["method"] : "GET", headers: { Authorization: `Basic ${this.auth}`, diff --git a/communication/graphql.ts b/communication/graphql.ts index 7fedf597..398f6fd9 100644 --- a/communication/graphql.ts +++ b/communication/graphql.ts @@ -41,6 +41,8 @@ export class GraphQL { * @return The instance of this class */ public addVariable(key: string, value: string): GraphQL { + // TODO: Find out type + // @ts-ignore See TODO this._variables[key] = value; return this; } diff --git a/communication/influxdb.ts b/communication/influxdb.ts index d5148921..3fcd9048 100644 --- a/communication/influxdb.ts +++ b/communication/influxdb.ts @@ -17,19 +17,17 @@ export class InfluxDB { private _api: Api; public constructor( - private readonly url: string, - private readonly token: string, + url: string, + token: string, + org: string, + bucket: string, + precision: Precision = Precision.us ) { - } - - public setApi(org: string, bucket: string, precision: Precision = Precision.us): this { this._api = { - url: `${this.url}/api/v2/write?org=${org}&bucket=${bucket}&precision=${Precision[precision]}`, - auth: `Token ${this.token}`, + url: `${url}/api/v2/write?org=${org}&bucket=${bucket}&precision=${Precision[precision]}`, + auth: `Token ${token}`, precision: precision, }; - - return this; } /** diff --git a/communication/nut.ts b/communication/nut.ts index b81f1c37..10118a95 100644 --- a/communication/nut.ts +++ b/communication/nut.ts @@ -6,8 +6,8 @@ export class NutState { } export class Nut { - private host: string = ""; - private port: number = 3493; + private readonly host: string = ""; + private readonly port: number = 3493; private client: Deno.TcpConn | null = null; private _status: number = NutState.IDLE; // deno-lint-ignore no-explicit-any -- TODO @@ -46,17 +46,17 @@ export class Nut { const data = new TextEncoder().encode(`${cmd}\n`); // Send our data over the connection - await this.client.write(data); + await this.client!.write(data); } public close() { //this.send(`LOGOUT`); - this.client.close(); + this.client!.close(); } private async onReceive() { // deno-lint-ignore no-deprecated-deno-api -- TODO - for await (const buffer of Deno.iter(this.client)) { + for await (const buffer of Deno.iter(this.client!)) { this.dataBuf += new TextDecoder().decode(buffer); this.callback(this.dataBuf); } diff --git a/core/cache.ts b/core/cache.ts index a57a60f2..951ae85e 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -54,7 +54,8 @@ export class Cache { case "total": return Cache._metrics.reads.hit + Cache._metrics.reads.miss; case "rate": { - const percentile = +(Cache._metrics.reads.hit / Cache.metrics("total")).toFixed(4); + const total: number = Cache.metrics("total") as number; + const percentile = +(Cache._metrics.reads.hit / total).toFixed(4); if(percentile > 0) return percentile; return 0; } @@ -234,12 +235,14 @@ export class Cache { * @param expiry * @param callable */ - public static async remember(key: string, expiry: string | null = "+1 minute", callable: Promise): Promise { + public static async remember(key: string, expiry: string | null = "+1 minute", callable: Promise): Promise { // Check if cache item exists and hasn't expired if(!Cache.expired(key)) return Cache.get(key); Cache._metrics.reads.miss++; // Cache does not exist, run callable + // TODO: Fix "no call signatures" in lint + // @ts-ignore See TODO const res = await callable(); // Add result to cache diff --git a/security/hash.ts b/security/hash.ts index 9421c968..fd35b37c 100644 --- a/security/hash.ts +++ b/security/hash.ts @@ -48,7 +48,7 @@ export const INSECURE_ALGORITHMS: string[] = [ ]; export class Hash { - private result: ArrayBuffer; + private result!: ArrayBuffer; constructor( private input: string, diff --git a/utility/empty.ts b/utility/empty.ts index 5cc177b9..f5b1ff04 100644 --- a/utility/empty.ts +++ b/utility/empty.ts @@ -5,7 +5,7 @@ * @returns boolean */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used -export default function empty(input: string | any[] | null): boolean { +export function empty(input: string | any[] | null): boolean { if (!input) return true; if (typeof input === "string") return input === ""; return input.length === 0; diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index b4d76efe..cc48ba8b 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -24,7 +24,8 @@ export class Controller { * @deprecated Please use "Controller.getResponse().withType()" instead. * @param value */ - public set type(value = "text/html") { + // @ts-ignore Deprecated function anyways + public set type(value: string = "text/html") { Logger.warning( 'Setting type on controller itself is deprecated, please use "Controller.getResponse().withType()" instead.', ); @@ -67,6 +68,8 @@ export class Controller { // Use that if so if (Registry.has(`${Inflector.ucfirst(name)}Component`)) { const module = Registry.get(`${Inflector.ucfirst(name)}Component`); + // TODO: Fix index signature + // @ts-ignore -- this[Inflector.ucfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); return this; } @@ -88,6 +91,8 @@ export class Controller { Registry.add(`${Inflector.ucfirst(name)}Component`, module); // Add the module as class property + // TODO: Fix index signature + // @ts-ignore -- this[Inflector.ucfirst(name)] = new module[`${Inflector.ucfirst(name)}Component`](this); return this; @@ -124,7 +129,8 @@ export class Controller { case "text/html": { const controller = Inflector.lcfirst(this.getRequest().getRoute().getController()); const action = this.getRequest().getRoute().getAction(); - body = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars); + const rendered = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars); + body = rendered ? rendered : ''; break; } case "application/octet-stream": { @@ -135,7 +141,7 @@ export class Controller { // Check if we can compress with Brotli // TODO: Hope that Deno will make this obsolete. - if (this.getRequest().getHeaders().get("accept-encoding")?.includes("br") && canCompress && body.length > 1024) { + if (this.getRequest().getHeaders().get("accept-encoding")?.includes("br") && canCompress && body.length > 1024 && typeof body === 'string') { Logger.debug(`Compressing body with brotli: ${body.length}-bytes`); body = compressBrotli(new TextEncoder().encode(body)); Logger.debug(`Compressed body with brotli: ${body.length}-bytes`); diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts index ca1fed46..a6e36f30 100644 --- a/webserver/http/response-builder.ts +++ b/webserver/http/response-builder.ts @@ -8,7 +8,7 @@ interface ResponseHeader { export class ResponseBuilder { private readonly _headers: Map> = new Map>(); private _status: StatusCodes = StatusCodes.OK; - private _body = ""; + private _body: string | Uint8Array = ""; public constructor() { // Set default headers @@ -110,7 +110,7 @@ export class ResponseBuilder { * * @param body */ - public withBody(body: string): ResponseBuilder { + public withBody(body: string|Uint8Array): ResponseBuilder { this._body = body; return this; } diff --git a/webserver/registry/registry.ts b/webserver/registry/registry.ts index 441c755d..2e80affa 100644 --- a/webserver/registry/registry.ts +++ b/webserver/registry/registry.ts @@ -1,5 +1,5 @@ interface RegistryItem { - [key: string]: Module; + [key: string]: any; } export class Registry { @@ -11,7 +11,7 @@ export class Registry { * @param name * @param module */ - public static add(name: string, module: Module): void { + public static add(name: string, module: any): void { Registry._items[name] = module; } @@ -20,7 +20,7 @@ export class Registry { * * @param name */ - public static get(name: string): Module | null { + public static get(name: string): any | null { return Registry._items[name] ?? null; } diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index eea312af..0d537fcf 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -23,6 +23,8 @@ export class Handlebars { // Compile our template // Cache it if need be + // TODO: Fix type + // @ts-ignore See TODO const compiled = hbs.compile(template) ?? raise("Could not compile template"); if (cache) Handlebars._cache[path] = compiled; diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 02bf102a..435f193e 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -173,8 +173,12 @@ export class Router { path = pathSplit[0]; const keys: string[] = []; + // TODO: Fix type error + // @ts-ignore -- const r = pathToRegexp(route.getPath(), keys).exec(path) || []; + // TODO: Fix type error + // @ts-ignore -- return keys.reduce((acc, key, i) => ({ [key.name]: r[i + 1], ...acc }), {}); } From a785a3ffb2b8d2ac0a2ada70bfa154196b20000d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 7 Dec 2024 16:45:57 +0100 Subject: [PATCH 250/379] Create new requireNotEmpty --- tests/util/contract.test.ts | 23 +++++++++++++++ utility/contract.ts | 57 +++++++++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/tests/util/contract.test.ts b/tests/util/contract.test.ts index 8ee68320..13c47f27 100644 --- a/tests/util/contract.test.ts +++ b/tests/util/contract.test.ts @@ -17,4 +17,27 @@ Deno.test("Contract Test", async (t) => { // Test when the argument is not null assert(() => Contract.requireNotNull("blabla", "testArgument")); }); + + await t.step("requireNotUndefined", () => { + // Test when the argument is undefined + assertThrows(() => Contract.requireNotUndefined(undefined, "testArgument")); + + // Test when the argument is not undefined + assert(() => Contract.requireNotUndefined("blabla", "testArgument")); + }); + + await t.step("requireNotEmpty", () => { + // Test when the argument is empty + assertThrows(() => Contract.requireNotEmpty(undefined)); + assertThrows(() => Contract.requireNotEmpty(null)); + assertThrows(() => Contract.requireNotEmpty("")); + assertThrows(() => Contract.requireNotEmpty([])); + assertThrows(() => Contract.requireNotEmpty({})); + + // Test when the argument is not undefined + assert(() => Contract.requireNotEmpty(0)); + assert(() => Contract.requireNotEmpty("blabla")); + assert(() => Contract.requireNotEmpty([])); + assert(() => Contract.requireNotEmpty({key: "value"})); + }) }); diff --git a/utility/contract.ts b/utility/contract.ts index 529b4658..24a2357f 100644 --- a/utility/contract.ts +++ b/utility/contract.ts @@ -1,4 +1,5 @@ import { raise } from "../error/raise.ts"; +import { nameOf } from "../mod.ts"; /** * Class to more easily throw errors while creating (among others) constructors. @@ -22,10 +23,12 @@ export class Contract { * @param message */ public static require(condition: boolean, message: string): void|never { - if (!condition) raise(message, "Argument"); + if (!condition) raise(message, "ContractRequirementFalse"); } /** + * Require the input argument to not be null + * * @example Basic Usage * ```ts * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; @@ -47,6 +50,56 @@ export class Contract { * @param argumentName */ public static requireNotNull(argument: unknown, argumentName: string): void|never { - if (argument === null) raise(`${argumentName} may not be null`, "ArgumentNull"); + if (argument === null) raise(`${argumentName} may not be null`, "ContractArgumentNull"); + } + + /** + * Require the input argument to not be undefined + * + * @example Basic Usage + * ```ts + * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; + * + * const myArgument = "blabla"; + * Contract.requireNotUndefined(myArgument, "myArgument"); + * ``` + * + * @example Using the {@linkcode nameOf} utility + * ```ts + * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; + * import { nameOf } from "https://deno.land/x/chomp/utility/name-of.ts"; + * + * const myArgument = "blabla"; + * Contract.requireNotUndefined(myArgument, nameOf({ myArgument })); + * ``` + * + * @param argument + * @param argumentName + */ + public static requireNotUndefined(argument: unknown, argumentName: string): void|never { + if(argument === undefined) raise(`${argumentName} may not be undefined`, "ContractArgumentUndefined"); + } + + /** + * Require the input argument to not be empty + * + * + * @param argument + */ + public static requireNotEmpty(argument: unknown): void|never { + // Check if undefined + if(argument === undefined) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); + + // Check if null + if(argument === null) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); + + // Check if empty string + if(argument === "") raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); + + // Check if empty array + if(Array.isArray(argument) && argument.length === 0) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); + + // Check if empty object + if(typeof argument === "object" && Object.keys(argument).length === 0) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); } } From bc6533c20e2dd0133443492ea231580903fd61b4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 7 Dec 2024 16:51:26 +0100 Subject: [PATCH 251/379] Add requireEmpty contract --- tests/util/contract.test.ts | 19 +++++++++++++++++-- utility/contract.ts | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/tests/util/contract.test.ts b/tests/util/contract.test.ts index 13c47f27..eff1fd75 100644 --- a/tests/util/contract.test.ts +++ b/tests/util/contract.test.ts @@ -34,10 +34,25 @@ Deno.test("Contract Test", async (t) => { assertThrows(() => Contract.requireNotEmpty([])); assertThrows(() => Contract.requireNotEmpty({})); - // Test when the argument is not undefined + // Test when the argument is not empty assert(() => Contract.requireNotEmpty(0)); assert(() => Contract.requireNotEmpty("blabla")); - assert(() => Contract.requireNotEmpty([])); + assert(() => Contract.requireNotEmpty([1])); assert(() => Contract.requireNotEmpty({key: "value"})); + }); + + await t.step("requireEmpty", () => { + // Test when the argument is not empty + assertThrows(() => Contract.requireEmpty(0)); + assertThrows(() => Contract.requireEmpty("blabla")); + assertThrows(() => Contract.requireEmpty([1])); + assertThrows(() => Contract.requireEmpty({key: "value"})); + + // Test when the argument is empty + assert(() => Contract.requireEmpty(undefined)); + assert(() => Contract.requireEmpty(null)); + assert(() => Contract.requireEmpty("")); + assert(() => Contract.requireEmpty([])); + assert(() => Contract.requireEmpty({})); }) }); diff --git a/utility/contract.ts b/utility/contract.ts index 24a2357f..5cdabdbb 100644 --- a/utility/contract.ts +++ b/utility/contract.ts @@ -102,4 +102,20 @@ export class Contract { // Check if empty object if(typeof argument === "object" && Object.keys(argument).length === 0) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); } + + /** + * Require the input argument to not be empty + * + * + * @param argument + */ + public static requireEmpty(argument: unknown): void|never { + try { + Contract.requireNotEmpty(argument); + } catch(e) { + return; + } + + raise(`${nameOf({ argument })} must be empty`, "ContractArgumentNotEmpty"); + } } From 5508ee75888309866a02b3e0cc2c27ce4b60e359 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 2 Jan 2025 09:02:39 +0100 Subject: [PATCH 252/379] Sweep cache every minute --- core/cache.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index 951ae85e..b95a1fdd 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -314,6 +314,6 @@ export class Cache { } } -// Sweep cache every hour +// Sweep cache every minute // @ts-ignore It's a function not a type -Cron("1 0 * * * *", () => Cache.sweep()); +Cron("0 */1 * * * *", () => Cache.sweep()); From 04a75a5e61325f0c24c29cbf4e6e8e990b6f864c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 2 Jan 2025 09:12:42 +0100 Subject: [PATCH 253/379] Add debug logs --- core/cache.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/cache.ts b/core/cache.ts index b95a1fdd..d9b4fbdf 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -279,6 +279,8 @@ export class Cache { * ``` */ public static sweep(): void { + Logger.debug('Starting cache sweep...'); + // Set the start time of this sweep // Set an optimistic boundary // TODO: Allow configuring of optimistic boundary @@ -311,6 +313,8 @@ export class Cache { Cache._items.delete(key); Cache._metrics.swept++; } + + Logger.debug('Finished cache sweep!'); } } From 114453659dad87b1f34b28f9736b66df72991874 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 10 Feb 2025 11:48:24 +0100 Subject: [PATCH 254/379] Update README.md --- README.md | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 632c8977..fe2b2f48 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Chomp -Library of (arguably) useful stuff.\ +Library of (arguably) useful stuff. +This library prioritizes "ease of use" over "efficiency". + Should work just fine but comes with no warranties whatsoever. ## Usage @@ -21,36 +23,17 @@ This includes (list might not always be up-to-date): - [Folder](docs/filesystem/folder.md) - [CheckSource](docs/utility/check-source.md) -You can then import any of the "extras" as you need: - -- [Discord Bot](docs/discord/README.md) (Discordeno Wrapper): - -```ts -import * from "https://deno.land/x/chomp/discord/mod.ts"; -``` - -- [Webserver](docs/webserver/README.md): - -```ts -import * from "https://deno.land/x/chomp/webserver/mod.ts"; -``` - -- [Websocket Server](docs/websocket/README.md): - -```ts -import * from "https://deno.land/x/chomp/websocket/mod.ts"; -``` - -Additionally, you can explore the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) +However, there are many more things included so feel free to explore the [docs](/docs) or [Deno.land](https://doc.deno.land/https://deno.land/x/chomp/mod.ts) to see what more Chomp is capable off! -**NOTE**: While you can import `https://deno.land/x/chomp/mod.ts`, we advice against this as it'll load the entire +**NOTE**: While you can import `https://deno.land/x/chomp/mod.ts`, I advice against this as it'll load the entire codebase, including stuff you may not actually be using. ## Versioning -Versions adhere to the following versioning system of `x.y.z` where: +As of `?.0.0.0`, versioning adheres to the following versioning system of `w.x.y.z` where: -- `x` means a breaking change (eg. removal of a function, breaking upgrade of an upstream dependency etc.). -- `y` means an addition or non-breaking update. -- `z` means a typos, bug-fix etc. +- `w` means all previous deprecations were removed. +- `x` means deprecations were added in this release. +- `y` means new features were added in this release. +- `z` means a small fix was made (typo's, bugs etc.) From 8f00952cd3e4f747c920ea35065a6992eabb6b1f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 10 Feb 2025 12:24:20 +0100 Subject: [PATCH 255/379] Update bunch of documentation --- communication/couchdb.ts | 3 +++ communication/druid.ts | 5 +++++ communication/graphql.ts | 3 +++ communication/influxdb.ts | 3 +++ communication/loki.ts | 3 +++ communication/ntfy.ts | 3 +++ communication/nut.ts | 3 +++ communication/rcon.ts | 3 +++ communication/redis.ts | 5 +++++ core/cache.ts | 3 +++ core/configure.ts | 5 ++++- core/logger.ts | 3 +++ error/error-codes.ts | 5 ++++- filesystem/file.ts | 5 +++++ filesystem/folder.ts | 5 +++++ queue/queue.ts | 3 +++ security/hash.ts | 5 +++++ security/password.ts | 9 +++++++++ security/random.ts | 3 +++ utility/empty.ts | 2 ++ utility/inflector.ts | 3 +++ utility/time-string.ts | 2 +- utility/time.ts | 5 +++++ 23 files changed, 86 insertions(+), 3 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index b9355d29..2a087534 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -25,6 +25,9 @@ export interface CouchOverrides { method?: string; } +/** + * Interact with {@link https://couchdb.apache.org/ Apache CouchDB}. + */ export class CouchDB { private auth = ""; diff --git a/communication/druid.ts b/communication/druid.ts index dd9ddb35..2be0b0d5 100644 --- a/communication/druid.ts +++ b/communication/druid.ts @@ -1,3 +1,8 @@ +/** + * Interact with {@link https://druid.apache.org/ Apache Druid}. + * + * @deprecated No longer actively maintained + */ export class Druid { // deno-lint-ignore no-explicit-any -- TODO private spec: any = null; diff --git a/communication/graphql.ts b/communication/graphql.ts index 398f6fd9..08678211 100644 --- a/communication/graphql.ts +++ b/communication/graphql.ts @@ -1,3 +1,6 @@ +/** + * Interact with a {@link https://graphql.org/ GraphQL} API. + */ export class GraphQL { private _variables = {}; private _query: string = "query{}"; diff --git a/communication/influxdb.ts b/communication/influxdb.ts index 3fcd9048..3e7de389 100644 --- a/communication/influxdb.ts +++ b/communication/influxdb.ts @@ -13,6 +13,9 @@ interface Api { precision: Precision; } +/** + * Interact with InfluxDB + */ export class InfluxDB { private _api: Api; diff --git a/communication/loki.ts b/communication/loki.ts index 3653325d..13214d77 100644 --- a/communication/loki.ts +++ b/communication/loki.ts @@ -6,6 +6,9 @@ export interface LokiStream { values: Array>; } +/** + * Interact with {@link https://grafana.com/oss/loki/ Loki}. + */ export class Loki { /** * @param host diff --git a/communication/ntfy.ts b/communication/ntfy.ts index 85e75dc6..9454a7ec 100644 --- a/communication/ntfy.ts +++ b/communication/ntfy.ts @@ -1,5 +1,8 @@ import { Logger } from "../core/logger.ts"; +/** + * Interact with Ntfy. + */ export class Ntfy { public constructor( private readonly host: string, diff --git a/communication/nut.ts b/communication/nut.ts index 10118a95..f5cee6c3 100644 --- a/communication/nut.ts +++ b/communication/nut.ts @@ -5,6 +5,9 @@ export class NutState { public static readonly IDLE = 1; } +/** + * Interact with NUT (Network UPS Tools). + */ export class Nut { private readonly host: string = ""; private readonly port: number = 3493; diff --git a/communication/rcon.ts b/communication/rcon.ts index d1d12852..13d27b07 100644 --- a/communication/rcon.ts +++ b/communication/rcon.ts @@ -5,6 +5,9 @@ export enum PacketType { AUTH = 0x03, } +/** + * Interact with RCON. + */ export class RCON { private conn!: Deno.Conn; diff --git a/communication/redis.ts b/communication/redis.ts index 2fbe8987..6d81fc4c 100644 --- a/communication/redis.ts +++ b/communication/redis.ts @@ -1,6 +1,11 @@ import { connect as redisConnect, Redis as RedisConn } from "https://deno.land/x/redis@v0.25.2/mod.ts"; import { Logger } from "../core/logger.ts"; +/** + * Interact with {@link https://redis.io/ Redis} using the {@link https://deno.land/x/redis@v0.25.2/mod.ts Redis library}. + * + * @deprecated No longer actively maintained + */ export class Redis { private static connection: RedisConn | null = null; diff --git a/core/cache.ts b/core/cache.ts index d9b4fbdf..913dd1cf 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -16,6 +16,9 @@ interface CacheMetrics { swept: number; } +/** + * Very crude but effective in-memory caching + */ export class Cache { private static _items: Map = new Map(); private static _metrics: CacheMetrics = { diff --git a/core/configure.ts b/core/configure.ts index b988f082..36a04e0e 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -6,13 +6,16 @@ const defaults = new Map([ ["error_log", `${Deno.cwd()}/logs/error.log`], ]); +/** + * In-memory configuration handler. + */ export class Configure { // deno-lint-ignore no-explicit-any -- Arbitrary data may be used private static config: Map = defaults; private static hasLoaded = false; /** - * Load our configure data from file + * Load our configure data from file at `${Deno.cwd()}/config.json`. * * @example Basic Usage * ```ts diff --git a/core/logger.ts b/core/logger.ts index 8f9bbedd..1f8c6927 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -45,6 +45,9 @@ const handlers: Handlers = { }, }; +/** + * Logging handler for writing to console + */ export class Logger { private static _handlers: Handlers = handlers; diff --git a/error/error-codes.ts b/error/error-codes.ts index c117c86b..8e1515da 100644 --- a/error/error-codes.ts +++ b/error/error-codes.ts @@ -1,3 +1,6 @@ +/** + * Standardized error codes, because nobody likes meaningless error codes. + */ export enum ErrorCodes { // Standard Errors UNKNOWN_ERROR = 0x0000000, @@ -16,7 +19,7 @@ export enum ErrorCodes { // Upstream Errors UPSTREAM_HTTP_BAD_REQUEST = 0x300400, - UPSTREAM_HTTP__UNAUTHORIZED = 0x300401, + UPSTREAM_HTTP_UNAUTHORIZED = 0x300401, UPSTREAM_HTTP_FORBIDDEN = 0x300403, UPSTREAM_HTTP_NOT_FOUND = 0x300404, UPSTREAM_HTTP_METHOD_NOT_ALLOWED = 0x300405, diff --git a/filesystem/file.ts b/filesystem/file.ts index 9cb4d116..47e6b3a3 100644 --- a/filesystem/file.ts +++ b/filesystem/file.ts @@ -1,3 +1,8 @@ +/** + * Interact with a file + * + * TODO: Finish documentation + */ export class File { public constructor( private readonly path: string, diff --git a/filesystem/folder.ts b/filesystem/folder.ts index a92b4d30..5396b724 100644 --- a/filesystem/folder.ts +++ b/filesystem/folder.ts @@ -1,5 +1,10 @@ import { Logger } from "../core/logger.ts"; +/** + * Interact with a file + * + * TODO: Finish documentation + */ export class Folder { public constructor( private readonly path: string, diff --git a/queue/queue.ts b/queue/queue.ts index 8cfc05e0..205cf5a1 100644 --- a/queue/queue.ts +++ b/queue/queue.ts @@ -17,6 +17,9 @@ export enum Scheduler { WEIGHTED = 2, } +/** + * Crude yet effective in-memory Queue system + */ export class Queue { private items: QueueItem[] = []; private readonly scheduler: Scheduler; diff --git a/security/hash.ts b/security/hash.ts index fd35b37c..f147b34c 100644 --- a/security/hash.ts +++ b/security/hash.ts @@ -47,6 +47,11 @@ export const INSECURE_ALGORITHMS: string[] = [ Algorithms.MD5, ]; +/** + * Create hashes + * + * **NOTE**: If you want to hash passwords, use the {@linkcode Password} class instead! + */ export class Hash { private result!: ArrayBuffer; diff --git a/security/password.ts b/security/password.ts index c372c782..8284fa8f 100644 --- a/security/password.ts +++ b/security/password.ts @@ -64,6 +64,15 @@ export interface PasswordOptions { allowInsecure?: boolean; } +/** + * Create password hashes and easily verify them. + * Automatically salts the hashes. + * + * Heavily inspired by PHP's {@link https://www.php.net/manual/en/function.password-hash.php password_hash} + * and {@link https://www.php.net/manual/en/function.password-verify.php password_verify} functions. + * + * **NOTE**: If you want to create deterministic hashes, use the {@linkcode Hash} class instead! + */ export class Password { /** * Hash the password using the specified password algorithm diff --git a/security/random.ts b/security/random.ts index 65a20555..a2703c06 100644 --- a/security/random.ts +++ b/security/random.ts @@ -1,3 +1,6 @@ +/** + * Create some randomness because I learned how to exit VIM. + */ export class Random { /** * Generate random bytes. diff --git a/utility/empty.ts b/utility/empty.ts index f5b1ff04..bde77467 100644 --- a/utility/empty.ts +++ b/utility/empty.ts @@ -1,6 +1,8 @@ /** * Check whether the input is set and empty * + * // TODO: Finish documentation + * * @param input * @returns boolean */ diff --git a/utility/inflector.ts b/utility/inflector.ts index 32b6e0e3..e9ad81a4 100644 --- a/utility/inflector.ts +++ b/utility/inflector.ts @@ -1,5 +1,8 @@ /** + * Quickly inflect text in common ways. * Idea and code primarily based on CakePHP's code. + * + * // TODO: Finish documentation */ export class Inflector { /** diff --git a/utility/time-string.ts b/utility/time-string.ts index 942182d0..40b38ba0 100644 --- a/utility/time-string.ts +++ b/utility/time-string.ts @@ -71,7 +71,7 @@ function parseNumberFormat(digit: string, unit: string): number { * * @example * ```ts - * import { TimeStringSeconds } from "https://deno.land/x/chomp/utility/time-string.ts"; + * import { TimeString } from "https://deno.land/x/chomp/utility/time-string.ts"; * * const milliseconds = TimeString`+1 minute`; * ``` diff --git a/utility/time.ts b/utility/time.ts index 22526246..2086159b 100644 --- a/utility/time.ts +++ b/utility/time.ts @@ -2,6 +2,11 @@ import { time as timets } from "https://denopkg.com/burhanahmeed/time.ts@v2.0.1/ import { format as formatter } from "https://cdn.deno.land/std/versions/0.77.0/raw/datetime/mod.ts"; import { TimeString } from "./time-string.ts"; +/** + * Try to alleviate the pain of working with time. + * + * // TODO: Finish documentation + */ export class Time { private readonly time; public get getTime() { From 7d7a6d1f239512a823e0c3ae1987354d85e3bc8e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 12 Feb 2025 21:44:15 +0100 Subject: [PATCH 256/379] Allow loading using config.ts to put developers in charge of their config --- core/configure.ts | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/core/configure.ts b/core/configure.ts index 36a04e0e..438f8757 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -15,7 +15,9 @@ export class Configure { private static hasLoaded = false; /** - * Load our configure data from file at `${Deno.cwd()}/config.json`. + * Load our configure data from file at `${Deno.cwd()}/config.json` or `${Deno.cwd()}/config.ts`. + * + * **NOTE**: Loading from `config.json` is deprecated and will be removed in the future but is currently still the default. * * @example Basic Usage * ```ts @@ -24,14 +26,46 @@ export class Configure { * await Configure.load(); * ``` * + * @example Load from config.ts + * ``` + * import { Configure } from "https://deno.land/x/chomp/core/configure.ts"; + * + * await Configure.load(false, true); + * ``` + * * @param force Set to true to force re-loading the configure + * @param useTs Set to true to load from config.ts instead of config.json * @returns void */ - public static async load(force = false): Promise { + public static async load(force = false, useTs = false): Promise { // Make sure we don't have loaded already if (Configure.hasLoaded === true && force === false) return; Logger.info(`Loading data into Configure...`); + if(!useTs) { + Logger.warning('Loading Configure from JSON is deprecated!'); + await Configure._loadJson(); + } else { + const module = await import(`file:///${Deno.cwd()}/config.ts`); + if(!('default' in module)) { + Logger.warning(`Could not load Configure: "${Deno.cwd()}/config.ts" has no default export...`); + Configure.hasLoaded = true; + return; + } + Configure.config = new Map(function*() { yield* defaults; yield* module['default']; }()); + } + + // Mark configure as loaded + Logger.info(`Finished loading Configure!`); + Configure.hasLoaded = true; + } + + /** + * Read the config.json file + * + * @deprecated Switching to using solely TS-based configs + */ + private static async _loadJson() { // Make sure our file exists try { await Deno.stat(`${Deno.cwd()}/config.json`); @@ -52,10 +86,6 @@ export class Configure { Logger.error(`Could not load JSON: "${e.message}"`, e.stack); return; } - - // Mark configure as loaded - Logger.info(`Finished loading Configure!`); - Configure.hasLoaded = true; } /** From 1cb57fe24b01f58102265c94dbc7eb3cfc0ed30e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 17 Apr 2025 20:58:53 +0200 Subject: [PATCH 257/379] Allow configuring optimistic boundary and significantly simplify the logic --- core/cache.ts | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index 913dd1cf..dc8a7429 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -1,10 +1,12 @@ import { TimeString } from "../utility/time-string.ts"; import { Logger } from "./logger.ts"; import { Cron } from "../utility/cron.ts"; +import { Configure } from "./configure.ts"; interface CacheItem { data: unknown; expires: Date | null; + optimistic?: Date; } interface CacheMetrics { @@ -16,8 +18,15 @@ interface CacheMetrics { swept: number; } +/** + * Default optimistic boundaries + */ +const OPTIMISTIC_DELAY = '+1 hour'; + /** * Very crude but effective in-memory caching + * + * You can specify additional time for optimistic caching by using the `chomp_optimistic_delay` configuration key. */ export class Cache { private static _items: Map = new Map(); @@ -93,11 +102,17 @@ export class Cache { */ public static set(key: string, value: unknown, expiry: string | null = "+1 minute"): void { let expiresAt = null; - if (expiry) expiresAt = new Date(new Date().getTime() + TimeString`${expiry}`); + let optimisticExpiry = undefined; + if (expiry) { + const now = new Date(); + expiresAt = new Date(now.getTime() + TimeString`${expiry}`); + optimisticExpiry = new Date(expiresAt.getTime() + TimeString`${Configure.get('chomp_optimistic_delay', OPTIMISTIC_DELAY)}`) + } Cache._items.set(key, { data: value, expires: expiresAt, + optimistic: optimisticExpiry }); Cache._metrics.writes++; } @@ -158,7 +173,7 @@ export class Cache { } /** - * Check whether an item has expired + * Check whether an item has expired. * * @example Basic Usage * ```ts @@ -285,11 +300,7 @@ export class Cache { Logger.debug('Starting cache sweep...'); // Set the start time of this sweep - // Set an optimistic boundary - // TODO: Allow configuring of optimistic boundary const now = new Date(); - const start = new Date(now.getTime() + TimeString`-1 hour -1 second`); - const boundary = new Date(now.getTime() + TimeString`-1 hour -1 minute`); // Loop over each item in the cache for (const [key, value] of Cache._items) { @@ -300,13 +311,13 @@ export class Cache { } // Keep items that have not yet expired - if (value.expires >= start) { + if (value.expires >= now) { Logger.debug(`Keeping cache item "${key}": Has not expired`); continue; } // Keep items that may be served optimistically - if (value.expires >= boundary) { + if (value.optimistic && value.optimistic >= now) { Logger.debug(`Keeping cache item "${key}": Keep for optimistic caching`); continue; } From 914ef5e0288b1cc9f42ef330712b44d21e13725d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 18 Apr 2025 13:03:56 +0200 Subject: [PATCH 258/379] Add UptimeKuma support and add utility for fetchWithTimeout --- communication/uptime-kuma.ts | 36 +++++++++++++++++++++++++++++++++++ mod.ts | 2 ++ utility/fetch-with-timeout.ts | 16 ++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 communication/uptime-kuma.ts create mode 100644 utility/fetch-with-timeout.ts diff --git a/communication/uptime-kuma.ts b/communication/uptime-kuma.ts new file mode 100644 index 00000000..956ccaa1 --- /dev/null +++ b/communication/uptime-kuma.ts @@ -0,0 +1,36 @@ +import {fetchWithTimeout} from "../utility/fetch-with-timeout.ts"; +import {raise} from "../mod.ts"; + +export interface UptimeKumaInstance { + host?: string; + id: string; +} + +export class UptimeKuma { + private readonly _host: string = 'http://localhost:3001'; + private readonly _id: string; + + public constructor(config: UptimeKumaInstance) { + if(config.host) this._host = config.host; + this._id = config.id; + } + + /** + * Send a heartbeat to Uptime Kuma + * + * @example + * ```ts + * const kuma = new UptimeKuma(data); + * await kuma.heartbeat(); + * ``` + */ + public async heartbeat(): Promise { + const resp = await fetchWithTimeout( + `${this._host}/api/push/${this._id}?status=up&msg=OK&ping=`, + {method: 'GET'}, + 5000 + ); + if(resp.status !== 200) raise(`Could not send heartbeat to Uptime Kuma: ${resp.status} - ${resp.statusText}`, 'UptimeKumaHeartbeatNotOK') + return true; + } +} diff --git a/mod.ts b/mod.ts index c0a32f38..0e07521a 100644 --- a/mod.ts +++ b/mod.ts @@ -10,6 +10,7 @@ export { Ntfy } from "./communication/ntfy.ts"; export { Nut } from "./communication/nut.ts"; export { RCON } from "./communication/rcon.ts"; export { Redis } from "./communication/redis.ts"; +export { UptimeKuma } from "./communication/uptime-kuma.ts"; /** * Chomp Core @@ -49,6 +50,7 @@ export { CheckSource } from "./utility/check-source.ts"; export { Contract } from "./utility/contract.ts"; export { Cron } from "./utility/cron.ts"; export { empty } from "./utility/empty.ts"; +export { fetchWithTimeout } from "./utility/fetch-with-timeout.ts"; export { formatBytes } from "./utility/format-bytes.ts"; export { Inflector } from "./utility/inflector.ts"; export { nameOf } from "./utility/name-of.ts"; diff --git a/utility/fetch-with-timeout.ts b/utility/fetch-with-timeout.ts new file mode 100644 index 00000000..14989b40 --- /dev/null +++ b/utility/fetch-with-timeout.ts @@ -0,0 +1,16 @@ +/** + * Allow running a fetch with a timeout + * + * @param input + * @param init + * @param timeout Milliseconds to wait before abording + */ +export function fetchWithTimeout(input: URL|Request|string, init: RequestInit = {}, timeout = 5000): Promise { + // Inject automatic abortion after 5 seconds + const controller = new AbortController(); + init.signal = controller.signal; + setTimeout(() => controller.abort(), timeout); + + // Create and return fetch + return fetch(input, init); +} From 02cdc1670e23b67e514c9f93ec58773f3dca1054 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 19 Apr 2025 17:15:09 +0200 Subject: [PATCH 259/379] Add function to delimit PascalCase strings. --- tests/util/inflector.test.ts | 7 +++++++ utility/inflector.ts | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/tests/util/inflector.test.ts b/tests/util/inflector.test.ts index 6a80edba..8057acd2 100644 --- a/tests/util/inflector.test.ts +++ b/tests/util/inflector.test.ts @@ -25,4 +25,11 @@ Deno.test("Inflector Test", async (t) => { assertEquals(Inflector.humanize("hello-world", "-"), "Hello World"); assertEquals(Inflector.humanize("hello_World", "-"), "Hello_World"); }); + + await t.step("delimit", () => { + assertEquals(Inflector.delimit("HelloWorld"), "hello_world"); + assertEquals(Inflector.delimit("HelloWorld", "-"), "hello-world"); + assertEquals(Inflector.delimit("Hello World"), "hello world"); + assertEquals(Inflector.delimit("Hello-World"), "hello-world"); + }) }); diff --git a/utility/inflector.ts b/utility/inflector.ts index e9ad81a4..64837f87 100644 --- a/utility/inflector.ts +++ b/utility/inflector.ts @@ -65,4 +65,10 @@ export class Inflector { // Join tokens into a string and return return tokens.join(" "); } + + public static delimit(input: string, delimiter: string = '_'): string { + return input + .replaceAll(/(?<=\w)([A-Z])/g, delimiter + '$1') + .toLowerCase(); + } } From 0b884fcf1cd998e8eb36cc02a4edeba6ca511672 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 19 Apr 2025 17:18:00 +0200 Subject: [PATCH 260/379] Add function to dasherize strings --- tests/util/inflector.test.ts | 7 ++++++- utility/inflector.ts | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/util/inflector.test.ts b/tests/util/inflector.test.ts index 8057acd2..0a9e0d47 100644 --- a/tests/util/inflector.test.ts +++ b/tests/util/inflector.test.ts @@ -26,10 +26,15 @@ Deno.test("Inflector Test", async (t) => { assertEquals(Inflector.humanize("hello_World", "-"), "Hello_World"); }); + await t.step("dasherize", () => { + assertEquals(Inflector.dasherize("HelloWorld"), "hello-world"); + assertEquals(Inflector.dasherize("hello_world"), "hello-world"); + }); + await t.step("delimit", () => { assertEquals(Inflector.delimit("HelloWorld"), "hello_world"); assertEquals(Inflector.delimit("HelloWorld", "-"), "hello-world"); assertEquals(Inflector.delimit("Hello World"), "hello world"); assertEquals(Inflector.delimit("Hello-World"), "hello-world"); - }) + }); }); diff --git a/utility/inflector.ts b/utility/inflector.ts index 64837f87..8833755e 100644 --- a/utility/inflector.ts +++ b/utility/inflector.ts @@ -66,6 +66,10 @@ export class Inflector { return tokens.join(" "); } + public static dasherize(input: string): string { + return Inflector.delimit(input.replaceAll('_', '-'), '-'); + } + public static delimit(input: string, delimiter: string = '_'): string { return input .replaceAll(/(?<=\w)([A-Z])/g, delimiter + '$1') From 32319d5ccf4db6fbd8d8af6b00486e4f276ae05e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 19 Apr 2025 17:19:12 +0200 Subject: [PATCH 261/379] Add comments --- utility/inflector.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/utility/inflector.ts b/utility/inflector.ts index 8833755e..9e0afdc0 100644 --- a/utility/inflector.ts +++ b/utility/inflector.ts @@ -66,10 +66,21 @@ export class Inflector { return tokens.join(" "); } + /** + * Returns the input CamelCasedString as a dashed-string and replace underscores with dashes + * + * @param input + */ public static dasherize(input: string): string { return Inflector.delimit(input.replaceAll('_', '-'), '-'); } + /** + * Expects a CamelCasedInputString, and produces a lower_case_delimited_string + * + * @param input + * @param delimiter + */ public static delimit(input: string, delimiter: string = '_'): string { return input .replaceAll(/(?<=\w)([A-Z])/g, delimiter + '$1') From e41c28faf1947cf16cfb5960d3d6f486ff95f1c4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 19 Apr 2025 17:42:28 +0200 Subject: [PATCH 262/379] Add bunch of caching --- utility/inflector.ts | 98 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 13 deletions(-) diff --git a/utility/inflector.ts b/utility/inflector.ts index 9e0afdc0..e5e811a7 100644 --- a/utility/inflector.ts +++ b/utility/inflector.ts @@ -1,7 +1,13 @@ +import { Cache } from "../core/cache.ts"; +import { Configure } from "../core/configure.ts"; + /** * Quickly inflect text in common ways. * Idea and code primarily based on CakePHP's code. * + * You can change the expiry time using the `chomp_inflector_cache_ttl` configuration key. + * Otherwise this will default to `+10 minutes`. + * * // TODO: Finish documentation */ export class Inflector { @@ -30,9 +36,22 @@ export class Inflector { * @param delimiter Optional delimiter by which to split the string */ public static pascalize(input: string, delimiter: string = "_"): string { - return this - .humanize(input, delimiter) - .replaceAll(" ", ""); + // Try to look up in cache + const type = `pascalize${delimiter}`; + let result = Inflector._cache(type, input); + + // Inflect on cache miss and add to cache + if(!result) { + // Humanize then remove spaces + result = this + .humanize(input, delimiter) + .replaceAll(" ", ""); + + // Add to Cache + Inflector._cache(type, input, result); + } + + return result; } /** @@ -53,17 +72,30 @@ export class Inflector { * @param delimiter */ public static humanize(input: string, delimiter: string = "_"): string { - // Split our string into tokens - const tokens: string[] = input - .split(delimiter); + // Try to look up in cache + const type = `humanize${delimiter}`; + let result = Inflector._cache(type, input); - // Uppercase each of the tokens - for (let i = 0; i < tokens.length; i++) { - tokens[i] = this.ucfirst(tokens[i]); + // Inflect on cache miss and add to cache + if(!result) { + // Split our string into tokens + const tokens: string[] = input + .split(delimiter); + + // Uppercase each of the tokens + for (let i = 0; i < tokens.length; i++) { + tokens[i] = this.ucfirst(tokens[i]); + } + + // Join tokens + result = tokens.join(" "); + + // Add to cache + Inflector._cache(type, input, result); } // Join tokens into a string and return - return tokens.join(" "); + return result; } /** @@ -82,8 +114,48 @@ export class Inflector { * @param delimiter */ public static delimit(input: string, delimiter: string = '_'): string { - return input - .replaceAll(/(?<=\w)([A-Z])/g, delimiter + '$1') - .toLowerCase(); + // Try to look up in cache + const type = `delimit${delimiter}`; + let result = Inflector._cache(type, input); + + // Inflect on cache miss and add to cache + if(!result) { + // Inflect + result = input + .replaceAll(/(?<=\w)([A-Z])/g, delimiter + '$1') + .toLowerCase(); + + // Add to cache + Inflector._cache(type, input, result); + } + + return result; + } + + /** + * Cache inflected valued and return if already available + * + * @param type Inflection type + * @param key Original value + * @param value Inflected value to cache + * @returns Inflected value on cache hit or false on cache miss + * @private + */ + private static _cache(type: string, key: string, value: string|false = false): string|false { + // Build cache key + const cacheKey = `chomp inflector ${type} "${key}"`; + + // Add to cache + if(value !== false) { + Cache.set(cacheKey, value, Configure.get('chomp_inflector_cache_ttl', '+10 minutes')); + return value; + } + + // Try to get from cache + const cached = Cache.get(cacheKey, true) as string|null; + if(cached !== null) return cached; + + // No result + return false; } } From f3101e5736d2815c3bff1f7dd474c63d7dd03c71 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 19 Apr 2025 17:44:20 +0200 Subject: [PATCH 263/379] Refactor a bit --- utility/inflector.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/utility/inflector.ts b/utility/inflector.ts index e5e811a7..18748193 100644 --- a/utility/inflector.ts +++ b/utility/inflector.ts @@ -38,7 +38,7 @@ export class Inflector { public static pascalize(input: string, delimiter: string = "_"): string { // Try to look up in cache const type = `pascalize${delimiter}`; - let result = Inflector._cache(type, input); + let result = this._cache(type, input); // Inflect on cache miss and add to cache if(!result) { @@ -48,7 +48,7 @@ export class Inflector { .replaceAll(" ", ""); // Add to Cache - Inflector._cache(type, input, result); + this._cache(type, input, result); } return result; @@ -74,7 +74,7 @@ export class Inflector { public static humanize(input: string, delimiter: string = "_"): string { // Try to look up in cache const type = `humanize${delimiter}`; - let result = Inflector._cache(type, input); + let result = this._cache(type, input); // Inflect on cache miss and add to cache if(!result) { @@ -91,7 +91,7 @@ export class Inflector { result = tokens.join(" "); // Add to cache - Inflector._cache(type, input, result); + this._cache(type, input, result); } // Join tokens into a string and return @@ -104,7 +104,7 @@ export class Inflector { * @param input */ public static dasherize(input: string): string { - return Inflector.delimit(input.replaceAll('_', '-'), '-'); + return this.delimit(input.replaceAll('_', '-'), '-'); } /** @@ -116,7 +116,7 @@ export class Inflector { public static delimit(input: string, delimiter: string = '_'): string { // Try to look up in cache const type = `delimit${delimiter}`; - let result = Inflector._cache(type, input); + let result = this._cache(type, input); // Inflect on cache miss and add to cache if(!result) { @@ -126,7 +126,7 @@ export class Inflector { .toLowerCase(); // Add to cache - Inflector._cache(type, input, result); + this._cache(type, input, result); } return result; From 9308cb33fc9b0078f56fad7b8cd3b9209ff796f0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 21 Apr 2025 13:02:45 +0200 Subject: [PATCH 264/379] Only return status code without message --- communication/uptime-kuma.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/uptime-kuma.ts b/communication/uptime-kuma.ts index 956ccaa1..d472ac85 100644 --- a/communication/uptime-kuma.ts +++ b/communication/uptime-kuma.ts @@ -30,7 +30,7 @@ export class UptimeKuma { {method: 'GET'}, 5000 ); - if(resp.status !== 200) raise(`Could not send heartbeat to Uptime Kuma: ${resp.status} - ${resp.statusText}`, 'UptimeKumaHeartbeatNotOK') + if(resp.status !== 200) raise(`${resp.status} - ${resp.statusText}`, 'UptimeKumaHeartbeatNotOK') return true; } } From 72f31d664fca7e5169cbcf5e7f4592c5cb01eb5f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 22 Apr 2025 12:30:20 +0200 Subject: [PATCH 265/379] Allow getting the name of the database --- communication/couchdb.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 2a087534..66affa5a 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -102,6 +102,21 @@ export class CouchDB { this.auth = btoa(`${username}:${password}`); } + /** + * Get the name of the database we're working with + * + * @example + * ```ts + * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; + * + * const couchdb = new CouchDB(...); + * const database = couchdb.databaseName; + * ``` + */ + public get databaseName(): string { + return this.database; + } + /** * Get a document from the database. * From a335be300683adfe7a8016a2fd5e8d20090dee55 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 18:32:50 +0200 Subject: [PATCH 266/379] Add function valueOrDefault --- utility/value-or-default.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 utility/value-or-default.ts diff --git a/utility/value-or-default.ts b/utility/value-or-default.ts new file mode 100644 index 00000000..17e4e9e8 --- /dev/null +++ b/utility/value-or-default.ts @@ -0,0 +1,16 @@ +/** + * Check if input has value, otherwise return a specified default + * + * @param input + * @param defaultValue + */ +export function valueOrDefault(input: unknown, defaultValue: unknown): unknown { + // Check if undefined + if(input === undefined) return defaultValue; + + // Check if null + if(input === null) return defaultValue; + + // We have a value just return the input + return input; +} From cfd2df775189e243ce26c474bbedd7e552e70351 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 18:45:13 +0200 Subject: [PATCH 267/379] Move code from Contract.requireNotEmpty to empty, and update Contracts. --- utility/contract.ts | 26 ++++---------------------- utility/empty.ts | 23 ++++++++++++++++++----- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/utility/contract.ts b/utility/contract.ts index 5cdabdbb..10895e53 100644 --- a/utility/contract.ts +++ b/utility/contract.ts @@ -1,5 +1,6 @@ import { raise } from "../error/raise.ts"; -import { nameOf } from "../mod.ts"; +import { empty } from "./empty.ts"; +import { nameOf } from "./name-of.ts"; /** * Class to more easily throw errors while creating (among others) constructors. @@ -87,20 +88,7 @@ export class Contract { * @param argument */ public static requireNotEmpty(argument: unknown): void|never { - // Check if undefined - if(argument === undefined) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); - - // Check if null - if(argument === null) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); - - // Check if empty string - if(argument === "") raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); - - // Check if empty array - if(Array.isArray(argument) && argument.length === 0) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); - - // Check if empty object - if(typeof argument === "object" && Object.keys(argument).length === 0) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty"); + if(empty(argument)) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty") } /** @@ -110,12 +98,6 @@ export class Contract { * @param argument */ public static requireEmpty(argument: unknown): void|never { - try { - Contract.requireNotEmpty(argument); - } catch(e) { - return; - } - - raise(`${nameOf({ argument })} must be empty`, "ContractArgumentNotEmpty"); + if(!empty(argument)) raise(`${nameOf({ argument })} must be empty`, "ContractArgumentNotEmpty"); } } diff --git a/utility/empty.ts b/utility/empty.ts index bde77467..c6b69b16 100644 --- a/utility/empty.ts +++ b/utility/empty.ts @@ -6,9 +6,22 @@ * @param input * @returns boolean */ -// deno-lint-ignore no-explicit-any -- Any arbitrary data may be used -export function empty(input: string | any[] | null): boolean { - if (!input) return true; - if (typeof input === "string") return input === ""; - return input.length === 0; +export function empty(input: unknown): boolean { + // Check if undefined + if(input === undefined) return true; + + // Check if null + if(input === null) return true; + + // Check if empty string + if(input === "") return true; + + // Check if empty array + if(Array.isArray(input) && input.length === 0) return true; + + // Check if empty object + if(typeof input === "object" && Object.keys(input).length === 0) return true; + + // We have something inside + return false; } From 968f332a2dfbbdf07d3be023e029eab8685dd9e7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 18:47:47 +0200 Subject: [PATCH 268/379] Add test runner configuration --- .run/Deno_ Test.run.xml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .run/Deno_ Test.run.xml diff --git a/.run/Deno_ Test.run.xml b/.run/Deno_ Test.run.xml new file mode 100644 index 00000000..9b85a6e0 --- /dev/null +++ b/.run/Deno_ Test.run.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From a2b5a562ff87bdb3b519b36fea3c996c61c16b40 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 20:09:46 +0200 Subject: [PATCH 269/379] Significantly simplify the statement --- utility/value-or-default.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/utility/value-or-default.ts b/utility/value-or-default.ts index 17e4e9e8..a2e7f7ae 100644 --- a/utility/value-or-default.ts +++ b/utility/value-or-default.ts @@ -5,12 +5,5 @@ * @param defaultValue */ export function valueOrDefault(input: unknown, defaultValue: unknown): unknown { - // Check if undefined - if(input === undefined) return defaultValue; - - // Check if null - if(input === null) return defaultValue; - - // We have a value just return the input - return input; + return input ?? defaultValue; } From d4cd90d4643829d2aea09035f204ede73fd4cc0f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 20:19:29 +0200 Subject: [PATCH 270/379] Fix issues with typing --- utility/value-or-default.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/value-or-default.ts b/utility/value-or-default.ts index a2e7f7ae..39ee5310 100644 --- a/utility/value-or-default.ts +++ b/utility/value-or-default.ts @@ -4,6 +4,6 @@ * @param input * @param defaultValue */ -export function valueOrDefault(input: unknown, defaultValue: unknown): unknown { +export function valueOrDefault(input: T, defaultValue: T): T { return input ?? defaultValue; } From e08490f11f23e3dd087e7cd65595c39d036b66ea Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 22:41:58 +0200 Subject: [PATCH 271/379] Fix type error when passing "undefined" to input --- utility/value-or-default.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/value-or-default.ts b/utility/value-or-default.ts index 39ee5310..f1905339 100644 --- a/utility/value-or-default.ts +++ b/utility/value-or-default.ts @@ -4,6 +4,6 @@ * @param input * @param defaultValue */ -export function valueOrDefault(input: T, defaultValue: T): T { +export function valueOrDefault(input: T|undefined, defaultValue: T): T { return input ?? defaultValue; } From 5c3bd694cca602a1efbcd6ea70972c8a53f62b9c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 22:52:11 +0200 Subject: [PATCH 272/379] Fix type error when passing "null" to input --- utility/value-or-default.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/value-or-default.ts b/utility/value-or-default.ts index f1905339..81cb1d1e 100644 --- a/utility/value-or-default.ts +++ b/utility/value-or-default.ts @@ -4,6 +4,6 @@ * @param input * @param defaultValue */ -export function valueOrDefault(input: T|undefined, defaultValue: T): T { +export function valueOrDefault(input: T|undefined|null, defaultValue: T): T { return input ?? defaultValue; } From 0e39f1dca6c918c40232405055233b90bc3c26b4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 23:16:06 +0200 Subject: [PATCH 273/379] Add typing for cache --- core/cache.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index dc8a7429..d7eeefdd 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -4,7 +4,8 @@ import { Cron } from "../utility/cron.ts"; import { Configure } from "./configure.ts"; interface CacheItem { - data: unknown; + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be added to cache + data: any; expires: Date | null; optimistic?: Date; } @@ -100,7 +101,8 @@ export class Cache { * @param value * @param expiry Can be set to null for never expiring items */ - public static set(key: string, value: unknown, expiry: string | null = "+1 minute"): void { + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be added to cache + public static set(key: string, value: any, expiry: string | null = "+1 minute"): void { let expiresAt = null; let optimisticExpiry = undefined; if (expiry) { @@ -137,7 +139,7 @@ export class Cache { * @param key * @param optimistic Whether to serve expired items from the cache */ - public static get(key: string, optimistic = false): unknown | null { + public static get(key: string, optimistic = false): T | null { // Return null if the item doesn't exist if (!Cache.exists(key)) { Cache._metrics.reads.miss++; @@ -207,9 +209,9 @@ export class Cache { * @param key * @param optimistic Whether to serve expired items from the cache */ - public static consume(key: string, optimistic = false): unknown | null { + public static consume(key: string, optimistic = false): T | null { // Copy item from cache - const data = Cache.get(key, optimistic); + const data = Cache.get(key, optimistic); // Remove item from cache Cache.remove(key); @@ -253,9 +255,9 @@ export class Cache { * @param expiry * @param callable */ - public static async remember(key: string, expiry: string | null = "+1 minute", callable: Promise): Promise { + public static async remember(key: string, expiry: string | null = "+1 minute", callable: Promise|(() => Promise)): Promise { // Check if cache item exists and hasn't expired - if(!Cache.expired(key)) return Cache.get(key); + if(!Cache.expired(key)) return Cache.get(key); Cache._metrics.reads.miss++; // Cache does not exist, run callable From 28d1160f259dd48eeca33c9076de0f99fabf0537 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 23:40:35 +0200 Subject: [PATCH 274/379] Add types for Configure --- core/configure.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/configure.ts b/core/configure.ts index 438f8757..e3a2ef7d 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -111,8 +111,7 @@ export class Configure { * @param defaultValue Default value to return when no result was found * @returns any|null */ - // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - public static get(key: string, defaultValue: any = null): any | null { + public static get(key: string, defaultValue: T|null = null): T | null { // Return null if we do not have the key if (!Configure.config.has(key)) return defaultValue; return Configure.config.get(key); @@ -180,8 +179,7 @@ export class Configure { * @param key * @param defaultValue */ - // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - public static consume(key: string, defaultValue: any = null): any { + public static consume(key: string, defaultValue: T|null = null): T|null { // Check if the key exists, if not, return the default value if (!Configure.config.has(key)) return defaultValue; From 795ae15865e429ec62aa09180325ac91c7c87ed7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Apr 2025 23:45:57 +0200 Subject: [PATCH 275/379] Allow returning null in valueOrDefault --- utility/value-or-default.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/value-or-default.ts b/utility/value-or-default.ts index 81cb1d1e..4cbae2b1 100644 --- a/utility/value-or-default.ts +++ b/utility/value-or-default.ts @@ -4,6 +4,6 @@ * @param input * @param defaultValue */ -export function valueOrDefault(input: T|undefined|null, defaultValue: T): T { +export function valueOrDefault(input: T|undefined|null, defaultValue: T|null): T|null { return input ?? defaultValue; } From 95110778d11d87ef6f5a308a0f3ecd70b376eea6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 27 Apr 2025 00:34:54 +0200 Subject: [PATCH 276/379] Update handling of Configure get and consume --- core/configure.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/configure.ts b/core/configure.ts index e3a2ef7d..92ff3f2e 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,4 +1,5 @@ import { Logger } from "./logger.ts"; +import {valueOrDefault} from "../utility/value-or-default.ts"; // deno-lint-ignore no-explicit-any -- Arbitrary data may be used const defaults = new Map([ @@ -111,10 +112,9 @@ export class Configure { * @param defaultValue Default value to return when no result was found * @returns any|null */ - public static get(key: string, defaultValue: T|null = null): T | null { + public static get(key: string, defaultValue: T|null = null): T { // Return null if we do not have the key - if (!Configure.config.has(key)) return defaultValue; - return Configure.config.get(key); + return valueOrDefault(Configure.config.get(key), defaultValue); } /** @@ -179,9 +179,9 @@ export class Configure { * @param key * @param defaultValue */ - public static consume(key: string, defaultValue: T|null = null): T|null { + public static consume(key: string, defaultValue: T|null = null): T { // Check if the key exists, if not, return the default value - if (!Configure.config.has(key)) return defaultValue; + if (!Configure.config.has(key)) return defaultValue as T; // Hack together a reference to our item's value const ref = [Configure.config.get(key)]; From 7fe22376486591a9f1d8cc93c50c3ef50bf1bc80 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 27 Apr 2025 00:46:15 +0200 Subject: [PATCH 277/379] Fix small error --- utility/value-or-default.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utility/value-or-default.ts b/utility/value-or-default.ts index 4cbae2b1..4263bc99 100644 --- a/utility/value-or-default.ts +++ b/utility/value-or-default.ts @@ -4,6 +4,6 @@ * @param input * @param defaultValue */ -export function valueOrDefault(input: T|undefined|null, defaultValue: T|null): T|null { - return input ?? defaultValue; +export function valueOrDefault(input: T|undefined|null, defaultValue: T|null = null): T { + return input ?? defaultValue as T; } From dea50e664b86af9ceecbc6121fb7d0223f1ff57d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 27 Apr 2025 20:02:50 +0200 Subject: [PATCH 278/379] Add sleep function --- utility/sleep.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 utility/sleep.ts diff --git a/utility/sleep.ts b/utility/sleep.ts new file mode 100644 index 00000000..cc529017 --- /dev/null +++ b/utility/sleep.ts @@ -0,0 +1,14 @@ +/** + * Sleep (non-blocking) for a defined amount of milliseconds. + * There generally should not be a reason to use it outside testing purposes. + * + * @example Basic usage + * ```ts + * // ... Do something + * await sleep(5_000); + * // ... Do more + * ``` + */ +export function sleep(milliseconds: number): Promise { + return new Promise(resolve => setTimeout(resolve, milliseconds)); +} From 9fbf8456f24cd45e22368c64357ec3ef25dc3880 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 5 May 2025 22:27:04 +0200 Subject: [PATCH 279/379] Allow dashed method names --- webserver/routing/router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 435f193e..17886c67 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -139,7 +139,7 @@ export class Router { await controller.initialize(); // Execute our action - await controller[req.getRoute().getAction()](); + await controller[Inflector.camelize(req.getRoute().getAction(), '-')](); // Render the body await controller.render(); From c3152ebadfa87ab2ec0357fb2da2e3c87dd70403 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 6 May 2025 16:34:29 +0200 Subject: [PATCH 280/379] Re-organize logger a bit and add notice level --- core/logger.ts | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/core/logger.ts b/core/logger.ts index 1f8c6927..46b41d3d 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -1,22 +1,17 @@ import { Time } from "../utility/time.ts"; import { Configure } from "./configure.ts"; -import { bold, cyan, magenta, red, yellow } from "https://deno.land/std@0.117.0/fmt/colors.ts"; +import { bold, cyan, magenta, red, yellow, blue } from "https://deno.land/std@0.117.0/fmt/colors.ts"; type Handlers = { - info: (message: string) => void; - warning: (message: string) => void; error: (message: string, stack: string | null) => void; + warning: (message: string) => void; + notice: (message: string) => void; + info: (message: string) => void; debug: (message: string) => void; }; type LogLevels = keyof Handlers; const handlers: Handlers = { - info: (message: string): void => { - console.log(`[${Logger.time()}] ${cyan("INFO")} > ${message}`); - }, - warning: (message: string): void => { - console.error(`[${Logger.time()}] ${yellow("WARN")} > ${message}`); - }, error: (message: string, stack: string | null = null): void => { // Get current time const now = Logger.time(); @@ -38,6 +33,15 @@ const handlers: Handlers = { if (stack) output += `\r\n${stack}`; console.error(output); }, + warning: (message: string): void => { + console.error(`[${Logger.time()}] ${yellow("WARN")} > ${message}`); + }, + notice: (message: string): void => { + console.error(`[${Logger.time()}] ${blue("NOTICE")}> ${message}`); + }, + info: (message: string): void => { + console.log(`[${Logger.time()}] ${cyan("INFO")} > ${message}`); + }, debug: (message: string): void => { if (Configure.get("debug", false)) { console.log(`[${Logger.time()}] ${magenta("DEBUG")} > ${message}`); @@ -63,13 +67,15 @@ export class Logger { } /** - * Write an info message to the console + * Write an error message to the console. + * If the "error_log" Configure item is set, will also write to file. * * @param {string} message The message to write + * @param {string|null} stack Optional stacktrace * @returns {void} */ - public static info(message: string): void { - Logger._handlers["info"](message); + public static error(message: string, stack: string | null = null): void { + Logger._handlers["error"](message, stack); } /** @@ -83,15 +89,23 @@ export class Logger { } /** - * Write an error message to the console. - * If the "error_log" Configure item is set, will also write to file. + * Write a notice to the console * * @param {string} message The message to write - * @param {string|null} stack Optional stacktrace * @returns {void} */ - public static error(message: string, stack: string | null = null): void { - Logger._handlers["error"](message, stack); + public static notice(message: string): void { + Logger._handlers["notice"](message); + } + + /** + * Write an info message to the console + * + * @param {string} message The message to write + * @returns {void} + */ + public static info(message: string): void { + Logger._handlers["info"](message); } /** From 2c378a2f44c0b2b33ae70a2c35967c0eda3b7e4d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 6 May 2025 16:43:05 +0200 Subject: [PATCH 281/379] Increase spacing a bit --- core/logger.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/logger.ts b/core/logger.ts index 46b41d3d..48f98bd8 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -29,22 +29,22 @@ const handlers: Handlers = { } // Write to console - let output = `[${now}] ${red(bold("ERROR"))} > ${message}`; + let output = `[${now}] ${red(bold("ERROR"))} > ${message}`; if (stack) output += `\r\n${stack}`; console.error(output); }, warning: (message: string): void => { - console.error(`[${Logger.time()}] ${yellow("WARN")} > ${message}`); + console.error(`[${Logger.time()}] ${yellow("WARN")} > ${message}`); }, notice: (message: string): void => { - console.error(`[${Logger.time()}] ${blue("NOTICE")}> ${message}`); + console.error(`[${Logger.time()}] ${blue("NOTICE")} > ${message}`); }, info: (message: string): void => { - console.log(`[${Logger.time()}] ${cyan("INFO")} > ${message}`); + console.log(`[${Logger.time()}] ${cyan("INFO")} > ${message}`); }, debug: (message: string): void => { if (Configure.get("debug", false)) { - console.log(`[${Logger.time()}] ${magenta("DEBUG")} > ${message}`); + console.log(`[${Logger.time()}] ${magenta("DEBUG")} > ${message}`); } }, }; From cf8c1beacea2d0403e28b69c42250b4ae8faf338 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 14 May 2025 09:39:23 +0200 Subject: [PATCH 282/379] Update versioning guidelines --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fe2b2f48..31077082 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,15 @@ codebase, including stuff you may not actually be using. ## Versioning -As of `?.0.0.0`, versioning adheres to the following versioning system of `w.x.y.z` where: - -- `w` means all previous deprecations were removed. -- `x` means deprecations were added in this release. -- `y` means new features were added in this release. -- `z` means a small fix was made (typo's, bugs etc.) +As of `?.0.0.0-0`, versioning adheres to the following versioning system of `a.b.c.d-e` where: + +- `a`: Some previous behaviour may have changed in a non-backwards compatible fashion (breaking). + - Impact: Serious updates may be required on your end. +- `b`: All previous deprecations were removed (potentially breaking). + - Impact: Nothing if you kept up with deprecations. +- `c`: Deprecations were added in this release. + - Impact: Deprecations may need to be fixed on your end. +- `d`: New feature(s) were added. + - Impact: New goodies for you to use. +- `e`: Small fixes (typo's, bugs, documentation etc.) + - Impact: Generally none. From 2f3d6ba9d8fa4023bd600cf54605f76187eb7896 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 15 May 2025 12:36:49 +0200 Subject: [PATCH 283/379] Cache responses when using "Couchdb.get()" --- communication/couchdb.ts | 115 ++++++++++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 25 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 66affa5a..6a590dc7 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -1,28 +1,45 @@ -interface Auth { +import { Cache } from "../core/cache.ts"; + +type Auth = { username: string; password: string; } - -interface CouchRequest { +type CouchRequest = { method: string; + // deno-lint-ignore no-explicit-any -- TODO: Figure out proper type headers: any; body?: string; } -export interface CouchResponse { - status: number; - statusText: string; +type CouchSuccess = { + ok: true; // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - data: any | null; - error: null | { + data: any; +} + +type CouchError = { + ok: false; + error: { error: string; reason: string; - }; + } } +type CachedResponse = { + etag: string; + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used + data: any; +} + +export type CouchResponse = { + status: number; + statusText: string; +} & (CouchSuccess | CouchError) + export interface CouchOverrides { method?: string; + etag?: string; } /** @@ -120,6 +137,8 @@ export class CouchDB { /** * Get a document from the database. * + * **Note**: Responses will always be cached. + * * @example * ```ts * import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts"; @@ -133,9 +152,28 @@ export class CouchDB { * ``` * * @param id + * @param cache */ - public async get(id: string): Promise { - return await this.raw(id); + public async get(id: string, cache: boolean = true): Promise { + // Check if we want to cache + // If not, just run the request + if(!cache) return this.raw(id); + + // Get the etag from cache + const cached = Cache.get(`chomp.couchdb.cache ${id}`) as CachedResponse|null; + + // Check if etag was found + // Run the request with or without it depending on result + let resp; + if(cached) { + resp = await this.raw(id, null, { + etag: cached.etag, + }); + } else { + resp = await this.raw(id); + } + + return resp; } /** @@ -224,9 +262,13 @@ export class CouchDB { const exists = await this.raw(id, null, { method: "GET" }); if (exists.status === 404) { data["_id"] = id; + delete data["_rev"]; return await this.insert(data); } + // Make sure we got an "OK" status before + if(!exists.ok) return exists; + // Update the document return await this.update(id, exists.data["_rev"], data); } @@ -333,6 +375,7 @@ export class CouchDB { method: overrides["method"] ? overrides["method"] : "GET", headers: { Authorization: `Basic ${this.auth}`, + "If-None-Match": overrides["etag"] ? overrides["etag"] : undefined, }, }; @@ -344,28 +387,50 @@ export class CouchDB { } // Make sure the endpoint starts with a leading slash + const cacheKey = endpoint; if (endpoint.charAt(0) !== "/" && endpoint !== "") endpoint = `/${endpoint}`; - // Send our request and get the response + // Send our request const resp = await fetch(`${this.host}/${this.database}${endpoint}`, opts); + + // Check if we have a 304 + // If so, get data from cache + if(resp.status === 304) { + const cached = Cache.get(`chomp.couchdb.cache ${cacheKey}`) as CachedResponse; + return cached.data; + } + + // Get data from request let data = null; if (opts.method !== "HEAD") data = await resp.json(); - // Prepare our CouchResponse - const couchResponse: CouchResponse = { - status: resp.status, - statusText: resp.statusText, - data: null, - error: null, - }; - // Check whether we have an error - if (resp.ok) { - couchResponse["data"] = data; - } else { - couchResponse["error"] = data; + if(!resp.ok) { + return { + ok: false, + status: resp.status, + statusText: resp.statusText, + error: data, + }; } - return couchResponse; + // Save etag and (slightly modified) response to cache + if(resp.headers.get("etag")) Cache.set(`chomp.couchdb.cache ${cacheKey}`, { + etag: resp.headers.get("etag"), + data: { + ok: true, + status: 200, + statusText: 'OK', + data: data, + }, + }); + + // Return our response + return { + ok: true, + status: resp.status, + statusText: resp.statusText, + data: data, + }; } } From 4d6b85a50f96d5575dd3776576909608866aa604 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 15 May 2025 12:39:37 +0200 Subject: [PATCH 284/379] Minor cleanups --- communication/couchdb.ts | 42 ++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 6a590dc7..7a096469 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -137,7 +137,7 @@ export class CouchDB { /** * Get a document from the database. * - * **Note**: Responses will always be cached. + * **Note**: Responses will always be stored in cache, regardless of the `cache` parameter. * * @example * ```ts @@ -154,26 +154,22 @@ export class CouchDB { * @param id * @param cache */ - public async get(id: string, cache: boolean = true): Promise { + public get(id: string, cache: boolean = true): Promise { // Check if we want to cache - // If not, just run the request + // If not, just run the request without etag if(!cache) return this.raw(id); // Get the etag from cache const cached = Cache.get(`chomp.couchdb.cache ${id}`) as CachedResponse|null; - // Check if etag was found - // Run the request with or without it depending on result - let resp; - if(cached) { - resp = await this.raw(id, null, { - etag: cached.etag, - }); - } else { - resp = await this.raw(id); - } + // Check if cached version was found + // If not, run the request without etag + if(!cached) return this.raw(id); - return resp; + // Run the request with the etag + return this.raw(id, null, { + etag: cached.etag, + }); } /** @@ -200,8 +196,8 @@ export class CouchDB { * @param data */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - public async insert(data: any): Promise { - return await this.raw("", data); + public insert(data: any): Promise { + return this.raw("", data); } /** @@ -227,12 +223,12 @@ export class CouchDB { * @param data */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - public async update(id: string, revision: string, data: any): Promise { + public update(id: string, revision: string, data: any): Promise { // Make sure the id and revision are set in the data if (!data["_id"] || data["_id"] !== id) data["_id"] = id; if (!data["_rev"] || data["_rev"] !== revision) data["_rev"] = revision; - return await this.raw(id, data, { method: "PUT" }); + return this.raw(id, data, { method: "PUT" }); } /** @@ -294,8 +290,8 @@ export class CouchDB { * @param id * @param revision */ - public async delete(id: string, revision: string): Promise { - return await this.raw(`${id}?rev=${revision}`, null, { method: "DELETE" }); + public delete(id: string, revision: string): Promise { + return this.raw(`${id}?rev=${revision}`, null, { method: "DELETE" }); } /** @@ -316,8 +312,8 @@ export class CouchDB { * @param view * @param partition */ - public async viewDesign(design: string, view: string, partition: string): Promise { - return await this.raw(`_partition/${partition}/_design/${design}/_view/${view}`); + public viewDesign(design: string, view: string, partition: string): Promise { + return this.raw(`_partition/${partition}/_design/${design}/_view/${view}`); } /** @@ -342,7 +338,7 @@ export class CouchDB { * @param selector * @param fields */ - public async find(selector: any, fields: string[]|null = null): Promise { + public find(selector: any, fields: string[]|null = null): Promise { // Instantiate body with selector const body: {selector: any, fields?:string[]} = { selector: selector, From 1cc1a124b0057982cafd950f4e0b2408a6ac8551 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 15 May 2025 12:41:16 +0200 Subject: [PATCH 285/379] Increase time we cache documents --- communication/couchdb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 7a096469..7ae7daf3 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -419,7 +419,7 @@ export class CouchDB { statusText: 'OK', data: data, }, - }); + }, "+1 hour"); // Return our response return { From d1ba49c38aa99c8173a9813d42ac0f236eeb2b9c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 15 May 2025 14:23:46 +0200 Subject: [PATCH 286/379] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 31077082..41715c7e 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,15 @@ to see what more Chomp is capable off! **NOTE**: While you can import `https://deno.land/x/chomp/mod.ts`, I advice against this as it'll load the entire codebase, including stuff you may not actually be using. +### Configuration keys + +While Chomp does try to have a lot of "good enough" defaults, sometimes you may want to set things to your own needs. +As a result, some things can be configured by you by adding entries to the Configure. + +| Key | Default Value | Comment | +|-----|---------------|--------------------------------------------------------------------------------------------------------| +| `chomp_optimistic_delay` | `'+1 hour'` | Additional time a cache entry may exist for optimistic caching. Uses the `utility/time-string` formats | + ## Versioning As of `?.0.0.0-0`, versioning adheres to the following versioning system of `a.b.c.d-e` where: From 0708191637403fc698fcc8ffc1a34b6e9e71fe30 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 15 May 2025 14:30:04 +0200 Subject: [PATCH 287/379] Allow specifying read cache timeout --- README.md | 5 +++-- communication/couchdb.ts | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 41715c7e..e5374cbb 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,10 @@ codebase, including stuff you may not actually be using. While Chomp does try to have a lot of "good enough" defaults, sometimes you may want to set things to your own needs. As a result, some things can be configured by you by adding entries to the Configure. -| Key | Default Value | Comment | -|-----|---------------|--------------------------------------------------------------------------------------------------------| +| Key | Default Value | Comment | +|-----|---------------|-------------------------------------------------------------------------------------------------------------------------------------| | `chomp_optimistic_delay` | `'+1 hour'` | Additional time a cache entry may exist for optimistic caching. Uses the `utility/time-string` formats | +| `chomp_couchdb_cache` | `'+1 hour'` | Time a document for `communication/couchdb` will be kept in the cache to improve read times. Uses the `utility/time-string` formats | ## Versioning diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 7ae7daf3..2a0ff6ad 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -1,4 +1,5 @@ import { Cache } from "../core/cache.ts"; +import {Configure} from "../core/configure.ts"; type Auth = { username: string; @@ -42,8 +43,12 @@ export interface CouchOverrides { etag?: string; } +const CACHE_TIME = '+1 hour'; + /** * Interact with {@link https://couchdb.apache.org/ Apache CouchDB}. + * + * You can specify the read cache expiry used for {@link CouchDB.get} by setting the `chomp_couchdb_cache` configuration key. */ export class CouchDB { private auth = ""; @@ -419,7 +424,7 @@ export class CouchDB { statusText: 'OK', data: data, }, - }, "+1 hour"); + }, Configure.get('chomp_couchdb_cache', CACHE_TIME)); // Return our response return { From 110186268bcf67cbbe2f4bba40216a6420068a8b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 16 May 2025 02:35:58 +0200 Subject: [PATCH 288/379] Minor cleanups and fix conflicts with cache when using upsert method --- communication/couchdb.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 2a0ff6ad..1bdb1443 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -260,18 +260,18 @@ export class CouchDB { public async upsert(id: string, data: any): Promise { // Check if a document already exists // Insert a new document if not - const exists = await this.raw(id, null, { method: "GET" }); + const exists = await this.get(id); if (exists.status === 404) { data["_id"] = id; delete data["_rev"]; - return await this.insert(data); + return this.insert(data); } // Make sure we got an "OK" status before if(!exists.ok) return exists; // Update the document - return await this.update(id, exists.data["_rev"], data); + return this.update(id, exists.data["_rev"], data); } /** @@ -403,7 +403,13 @@ export class CouchDB { // Get data from request let data = null; - if (opts.method !== "HEAD") data = await resp.json(); + if (!["HEAD","PUT"].includes(opts.method)) data = await resp.json(); + if(opts.method === "PUT") { + data = body; + + // Overwrite revision with revision from the etag to prevent conflicts + if(resp.headers.get("etag")) data._rev = resp.headers.get("etag")!.replaceAll("\"", ""); + } // Check whether we have an error if(!resp.ok) { From d727f55d72b2a927fac1a7fe1aaadbbd2bcd0fa4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 18 May 2025 18:05:54 +0200 Subject: [PATCH 289/379] Add document header type --- communication/couchdb.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 1bdb1443..525d49a8 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -43,6 +43,11 @@ export interface CouchOverrides { etag?: string; } +export type DocumentHeader = { + _id: string; + _rev?: string; +} + const CACHE_TIME = '+1 hour'; /** From 069684611b021896b514c728b1d8ec6db6ebb61f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 23 May 2025 12:28:40 +0200 Subject: [PATCH 290/379] Fix bug with trying to get expired cache --- communication/couchdb.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 525d49a8..f0f9ce67 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -29,8 +29,7 @@ type CouchError = { type CachedResponse = { etag: string; - // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - data: any; + data: CouchResponse; } export type CouchResponse = { @@ -401,10 +400,8 @@ export class CouchDB { // Check if we have a 304 // If so, get data from cache - if(resp.status === 304) { - const cached = Cache.get(`chomp.couchdb.cache ${cacheKey}`) as CachedResponse; - return cached.data; - } + const cached = Cache.get(`chomp.couchdb.cache ${cacheKey}`) as CachedResponse + if(resp.status === 304 && cached) return cached.data; // Get data from request let data = null; From c96706c273245c187f169e671c5cbb46a0c255a0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 26 May 2025 21:50:26 +0200 Subject: [PATCH 291/379] Return earlier if we have an error --- communication/couchdb.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index f0f9ce67..af78aa58 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -403,6 +403,17 @@ export class CouchDB { const cached = Cache.get(`chomp.couchdb.cache ${cacheKey}`) as CachedResponse if(resp.status === 304 && cached) return cached.data; + // Check whether we have an error + // If so, return + if(!resp.ok) { + return { + ok: false, + status: resp.status, + statusText: resp.statusText, + error: await resp.json(), + }; + } + // Get data from request let data = null; if (!["HEAD","PUT"].includes(opts.method)) data = await resp.json(); @@ -413,16 +424,6 @@ export class CouchDB { if(resp.headers.get("etag")) data._rev = resp.headers.get("etag")!.replaceAll("\"", ""); } - // Check whether we have an error - if(!resp.ok) { - return { - ok: false, - status: resp.status, - statusText: resp.statusText, - error: data, - }; - } - // Save etag and (slightly modified) response to cache if(resp.headers.get("etag")) Cache.set(`chomp.couchdb.cache ${cacheKey}`, { etag: resp.headers.get("etag"), From f12de15dbfdad8391417596120252670d47fc0e0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 26 May 2025 21:56:48 +0200 Subject: [PATCH 292/379] Get data (or not) based on request method --- communication/couchdb.ts | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index af78aa58..a1c644da 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -416,12 +416,20 @@ export class CouchDB { // Get data from request let data = null; - if (!["HEAD","PUT"].includes(opts.method)) data = await resp.json(); - if(opts.method === "PUT") { - data = body; - - // Overwrite revision with revision from the etag to prevent conflicts - if(resp.headers.get("etag")) data._rev = resp.headers.get("etag")!.replaceAll("\"", ""); + switch(opts.method.toUpperCase()) { + case "HEAD": + case "DELETE": + break; + case "PUT": + // Put input body as data since CouchDB doesn't send this back + data = body; + + // Overwrite revision with revision from the etag to prevent conflicts + if(resp.headers.get("etag")) data._rev = resp.headers.get("etag")!.replaceAll("\"", ""); + break; + case "GET": + data = await resp.json(); + break; } // Save etag and (slightly modified) response to cache From 97900067b39dbf3c250985c758f4b8cb5352efb5 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 26 May 2025 23:11:36 +0200 Subject: [PATCH 293/379] Parse body on POST request --- communication/couchdb.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index a1c644da..0ef05935 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -427,6 +427,7 @@ export class CouchDB { // Overwrite revision with revision from the etag to prevent conflicts if(resp.headers.get("etag")) data._rev = resp.headers.get("etag")!.replaceAll("\"", ""); break; + case "POST": case "GET": data = await resp.json(); break; From 329efc633b3c397f08eefc7126ee8aedfff2411e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 26 May 2025 23:37:23 +0200 Subject: [PATCH 294/379] Add new issue templatesUpdate issue and PR template --- .github/ISSUE_TEMPLATE/1-feature_request.yml | 28 ++++++++++++ .github/ISSUE_TEMPLATE/2-bug_report.yml | 46 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 1 + .github/pull_request_template.md | 2 +- 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/1-feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/2-bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/1-feature_request.yml b/.github/ISSUE_TEMPLATE/1-feature_request.yml new file mode 100644 index 00000000..58e95485 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-feature_request.yml @@ -0,0 +1,28 @@ +name: Feature Request +description: Suggest an idea for Chomp! +title: 'Suggestion: ' +body: + - type: textarea + attributes: + label: Tell us what problem the feature would solve + description: Provide as much information as possible and please be descriptive. + validations: + required: true + - type: textarea + attributes: + label: Describe the solution you'd like + description: A clear and concise description of what you want to happen. + validations: + required: true + - type: textarea + attributes: + label: Did you consider any alternatives? If so, why is this the best? + description: A clear and concise description of any alternative solutions or features you've considered but why you've picked this one. + validations: + required: true + - type: textarea + attributes: + label: Additional Info + description: If applicable, add any other context or screenshots about the feature request here. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/2-bug_report.yml b/.github/ISSUE_TEMPLATE/2-bug_report.yml new file mode 100644 index 00000000..85d7379a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-bug_report.yml @@ -0,0 +1,46 @@ +name: Bug Report +description: File a bug report. +title: "Bug: " +body: + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Provide as much information as possible and please be descriptive. + validations: + required: true + - type: dropdown + id: runtime + attributes: + label: Runtime + description: What runtime (Node, Deno, etc) are you using? + options: + - Deno + - NodeJS + - Bun + - Other (add the name to the version) + default: 0 + validations: + required: true + - type: input + id: runtime-version + attributes: + label: Runtime Version + description: What version of the runtime are you using? In Deno you could get this through `deno --version`. + placeholder: 1.46.3 + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: checkboxes + id: latest + attributes: + label: Latest Release + description: By submitting this issue, you confirm that you are using the latest release when this issue is present. + options: + - label: I confirm that I am running on the latest release. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..0086358d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: true diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 13acebbb..c9c8ff9d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -22,6 +22,6 @@ I made this PR because ... - [ ] Changes have no left-over console logs. - [ ] Changes have no left-over debuggers. -- [ ] Changes have no left-over other pieces or code. +- [ ] Changes have no left-over "other pieces or code". - [ ] Changes have kept the documentation in-sync with the code as much as possible. - [ ] Changes still look good after taking a break and coming in cold. From d887f100444869da089659ea5055144eebce3926 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 26 May 2025 23:50:51 +0200 Subject: [PATCH 295/379] Allow generating odd string lengths (closes #6) --- security/random.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/security/random.ts b/security/random.ts index a2703c06..75e4636a 100644 --- a/security/random.ts +++ b/security/random.ts @@ -38,9 +38,23 @@ export class Random { * @param length Length of the string to be generated * @returns Promise */ - public static async string(length: number): Promise { - const buf = await Random.bytes(length / 2); - return Array.from(buf, (dec: number) => dec.toString(16).padStart(2, "0")).join(""); + public static string(length: number): string { + // Calculate how much bytes we need to generate to fulfill this request + // If we have an odd number, generate one extra byte + let generateLength = length; + if(generateLength % 2 !== 0) generateLength++; + + // Generate our random bytes + const buf = Random.bytes(generateLength / 2); + + // Turn bytes into string + const str = + Array + .from(buf, (dec: number) => dec.toString(16).padStart(2, "0")) + .join(""); + + // Return requested length + return str.substring(0, length); } /** From e98288a07c605d4ae06d43197387eb9940852436 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 27 May 2025 21:44:52 +0200 Subject: [PATCH 296/379] Only parse error object if it's a 404, otherwise return a generic one --- communication/couchdb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 0ef05935..3248c2fa 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -410,7 +410,7 @@ export class CouchDB { ok: false, status: resp.status, statusText: resp.statusText, - error: await resp.json(), + error: resp.status === 404 ? await resp.json() : { error: resp.status, reason: resp.statusText }, }; } From 08cc5982f61e08cbb93b3b4ce76b68cffe1aa282 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 28 May 2025 15:01:39 +0200 Subject: [PATCH 297/379] Put cache sweeping in the hands of the app to allow for more flexibility --- core/cache.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index d7eeefdd..b1320150 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -27,7 +27,7 @@ const OPTIMISTIC_DELAY = '+1 hour'; /** * Very crude but effective in-memory caching * - * You can specify additional time for optimistic caching by using the `chomp_optimistic_delay` configuration key. + * Running {@linkcode Cache.sweep} is up to the app itself. */ export class Cache { private static _items: Map = new Map(); @@ -289,7 +289,6 @@ export class Cache { /** * Scan the cache and clean up expired items while keeping optimistic caching in tact. - * There shouldn't be a need to manually run this in most cases. * * @example Basic Usage * ```ts @@ -333,7 +332,3 @@ export class Cache { Logger.debug('Finished cache sweep!'); } } - -// Sweep cache every minute -// @ts-ignore It's a function not a type -Cron("0 */1 * * * *", () => Cache.sweep()); From 193d899b29adca03f5dd61131820bc75b70baaf7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 30 May 2025 07:14:43 +0200 Subject: [PATCH 298/379] Add "errorOrData" utility --- mod.ts | 1 + tests/util/error-or-data.test.ts | 40 ++++++++++++++++++++++++++++++++ utility/error-or-data.ts | 17 ++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 tests/util/error-or-data.test.ts create mode 100644 utility/error-or-data.ts diff --git a/mod.ts b/mod.ts index 0e07521a..68387bc1 100644 --- a/mod.ts +++ b/mod.ts @@ -50,6 +50,7 @@ export { CheckSource } from "./utility/check-source.ts"; export { Contract } from "./utility/contract.ts"; export { Cron } from "./utility/cron.ts"; export { empty } from "./utility/empty.ts"; +export { errorOrData } from "./utility/error-or-data.ts"; export { fetchWithTimeout } from "./utility/fetch-with-timeout.ts"; export { formatBytes } from "./utility/format-bytes.ts"; export { Inflector } from "./utility/inflector.ts"; diff --git a/tests/util/error-or-data.test.ts b/tests/util/error-or-data.test.ts new file mode 100644 index 00000000..79b1cdc7 --- /dev/null +++ b/tests/util/error-or-data.test.ts @@ -0,0 +1,40 @@ +import { errorOrData } from "../../utility/error-or-data.ts"; +import { assertEquals, assertRejects, assertInstanceOf } from "https://deno.land/std@0.152.0/testing/asserts.ts"; +import {assertNotInstanceOf} from "https://deno.land/std@0.159.0/testing/asserts.ts"; + +class AError extends Error { + name = "AError"; +} + +class BError extends Error { + name = "BError"; +} + +async function good() { + return "foo"; +} + +async function bad() { + throw new AError('AError'); +} + +Deno.test("errorOrData Test", async (t) => { + // Test where the result would be good + await t.step("Good", async () => { + assertEquals(await errorOrData(good()), [undefined, "foo"]); + }); + + // Test where the result would be a caught AError + await t.step("Bad (Caught)", async () => { + const [error, _data] = await errorOrData(bad(), [AError]); + assertInstanceOf(error, AError); + assertNotInstanceOf(error, BError); + }); + + // Test where the result would be a thrown BError + await t.step("Bad (Uncaught)", () => { + assertRejects(async () => { + const [_error, _data] = await errorOrData(bad(), [BError]); + }); + }); +}); diff --git a/utility/error-or-data.ts b/utility/error-or-data.ts new file mode 100644 index 00000000..78fa7dcb --- /dev/null +++ b/utility/error-or-data.ts @@ -0,0 +1,17 @@ +type SuccessResponse = [undefined, T]; + +export async function errorOrData Error>(promise: Promise, catchables?: E[]): Promise | [InstanceType]> { + try { + const data = await promise; + return [undefined, data] as SuccessResponse; + } catch (error) { + // If no catchables are defined just return all errors + if (catchables === undefined) return [error]; + + // Check if our error is any of the catchables + if (catchables.some((e: E): boolean => error instanceof e)) return [error]; + + // Throw the error + throw error; + } +} From 9a5366d442cfe9910fa25e300f15bf4584c0b69b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Fri, 30 May 2025 23:31:09 +0200 Subject: [PATCH 299/379] Change the way errors and successes are handled --- communication/couchdb.ts | 75 +++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 3248c2fa..97a9af55 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -13,29 +13,35 @@ type CouchRequest = { body?: string; } -type CouchSuccess = { - ok: true; - // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - data: any; -} - -type CouchError = { - ok: false; - error: { - error: string; - reason: string; - } -} - type CachedResponse = { etag: string; data: CouchResponse; } -export type CouchResponse = { - status: number; - statusText: string; -} & (CouchSuccess | CouchError) +export type CouchFailure = [ + // Error data + { error: string; reason: string; } | undefined, + + // No document + undefined, + + // HTTP Status code + number, +] + +export type CouchSuccess = [ + // No error + undefined, + + // Document + // deno-lint-ignore no-explicit-any -- TODO: Figure out proper type + DocumentHeader & any, + + // HTTP Status code + number, +] + +export type CouchResponse = CouchSuccess|CouchFailure; export interface CouchOverrides { method?: string; @@ -264,18 +270,18 @@ export class CouchDB { public async upsert(id: string, data: any): Promise { // Check if a document already exists // Insert a new document if not - const exists = await this.get(id); - if (exists.status === 404) { + const [error, document, status] = await this.get(id); + if (status === 404) { data["_id"] = id; delete data["_rev"]; return this.insert(data); } // Make sure we got an "OK" status before - if(!exists.ok) return exists; + if(error) return [error, document, status]; // Update the document - return this.update(id, exists.data["_rev"], data); + return this.update(id, document["_rev"], data); } /** @@ -406,12 +412,11 @@ export class CouchDB { // Check whether we have an error // If so, return if(!resp.ok) { - return { - ok: false, - status: resp.status, - statusText: resp.statusText, - error: resp.status === 404 ? await resp.json() : { error: resp.status, reason: resp.statusText }, - }; + return [ + resp.status === 404 ? await resp.json() : { error: resp.status, reason: resp.statusText }, + undefined, + resp.status, + ]; } // Get data from request @@ -436,20 +441,10 @@ export class CouchDB { // Save etag and (slightly modified) response to cache if(resp.headers.get("etag")) Cache.set(`chomp.couchdb.cache ${cacheKey}`, { etag: resp.headers.get("etag"), - data: { - ok: true, - status: 200, - statusText: 'OK', - data: data, - }, + data: [undefined, data, 200], }, Configure.get('chomp_couchdb_cache', CACHE_TIME)); // Return our response - return { - ok: true, - status: resp.status, - statusText: resp.statusText, - data: data, - }; + return [undefined, data, resp.status]; } } From fc99dc6c91ed1f49fbc804229f836276f237629a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 3 Jun 2025 01:51:34 +0200 Subject: [PATCH 300/379] Add trace and monitor methods to logger --- core/logger.ts | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/core/logger.ts b/core/logger.ts index 48f98bd8..96784566 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -1,13 +1,15 @@ import { Time } from "../utility/time.ts"; import { Configure } from "./configure.ts"; -import { bold, cyan, magenta, red, yellow, blue } from "https://deno.land/std@0.117.0/fmt/colors.ts"; +import { bold, cyan, magenta, red, yellow, blue, green, gray } from "https://deno.land/std@0.117.0/fmt/colors.ts"; type Handlers = { error: (message: string, stack: string | null) => void; warning: (message: string) => void; notice: (message: string) => void; info: (message: string) => void; + monitor: (message: string) => void; debug: (message: string) => void; + trace: (message: string) => void; }; type LogLevels = keyof Handlers; @@ -42,11 +44,19 @@ const handlers: Handlers = { info: (message: string): void => { console.log(`[${Logger.time()}] ${cyan("INFO")} > ${message}`); }, + monitor: (message: string): void => { + console.log(`[${Logger.time()}] ${green("MON")} > ${message}`); + }, debug: (message: string): void => { if (Configure.get("debug", false)) { console.log(`[${Logger.time()}] ${magenta("DEBUG")} > ${message}`); } }, + trace: (message: string): void => { + if (Configure.get("debug", false)) { + console.log(`[${Logger.time()}] ${gray("TRACE")} > ${message}`); + } + } }; /** @@ -108,9 +118,21 @@ export class Logger { Logger._handlers["info"](message); } + /** + * Write a monitor message to the console + * + * Useful for when you want to write performance-related messages + * + * @param message + * @returns {void} + */ + public static monitor(message: string): void { + Logger._handlers["monitor"](message); + } + /** * Write a debug message to the console - * Only shows up when the "DEBUG" env is set to truthy + * By default, only shows up when the "DEBUG" env is set to truthy * * @param {string} message The message to write * @returns {void} @@ -119,6 +141,17 @@ export class Logger { Logger._handlers["debug"](message); } + /** + * Write a trace message to the console. + * By default, only shows up when the "DEBUG" env is set to truthy. + * + * @param message + * @returns {void} + */ + public static trace(message: string): void { + Logger._handlers["trace"](message); + } + /** * Return the current time in format. * Configurable using the "logger.timeformat" key. From 6d262ab680e6fe916d6793c5785aa2e031e03244 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 3 Jun 2025 01:55:40 +0200 Subject: [PATCH 301/379] Change default text a bit --- core/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/logger.ts b/core/logger.ts index 96784566..123a4032 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -45,7 +45,7 @@ const handlers: Handlers = { console.log(`[${Logger.time()}] ${cyan("INFO")} > ${message}`); }, monitor: (message: string): void => { - console.log(`[${Logger.time()}] ${green("MON")} > ${message}`); + console.log(`[${Logger.time()}] ${green("MONIT")} > ${message}`); }, debug: (message: string): void => { if (Configure.get("debug", false)) { From 9b6461f63347e3b12c3de70afa4c6e8f04226287 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 3 Jun 2025 02:08:09 +0200 Subject: [PATCH 302/379] Allow slightly more finegrained control over log levels. --- core/configure.ts | 1 + core/logger.ts | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/core/configure.ts b/core/configure.ts index 92ff3f2e..40708b88 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -4,6 +4,7 @@ import {valueOrDefault} from "../utility/value-or-default.ts"; // deno-lint-ignore no-explicit-any -- Arbitrary data may be used const defaults = new Map([ ["debug", false], + ["log_level", 5], ["error_log", `${Deno.cwd()}/logs/error.log`], ]); diff --git a/core/logger.ts b/core/logger.ts index 123a4032..e6728216 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -80,6 +80,8 @@ export class Logger { * Write an error message to the console. * If the "error_log" Configure item is set, will also write to file. * + * Available in any log level. + * * @param {string} message The message to write * @param {string|null} stack Optional stacktrace * @returns {void} @@ -91,65 +93,75 @@ export class Logger { /** * Write a warning message to the console * + * Available in log levels 0 and higher. + * * @param {string} message The message to write * @returns {void} */ public static warning(message: string): void { - Logger._handlers["warning"](message); + if(Logger.shouldLog(0)) Logger._handlers["warning"](message); } /** * Write a notice to the console * + * Available in log levels 1 and higher. + * * @param {string} message The message to write * @returns {void} */ public static notice(message: string): void { - Logger._handlers["notice"](message); + if(Logger.shouldLog(1)) Logger._handlers["notice"](message); } /** * Write an info message to the console * + * Available in log levels 2 and higher. + * * @param {string} message The message to write * @returns {void} */ public static info(message: string): void { - Logger._handlers["info"](message); + if(Logger.shouldLog(2)) Logger._handlers["info"](message); } /** * Write a monitor message to the console - * * Useful for when you want to write performance-related messages * + * Available in log levels 3 and higher. + * * @param message * @returns {void} */ public static monitor(message: string): void { - Logger._handlers["monitor"](message); + if(Logger.shouldLog(3)) Logger._handlers["monitor"](message); } /** * Write a debug message to the console - * By default, only shows up when the "DEBUG" env is set to truthy + * + * Available in log levels 4 and higher. * * @param {string} message The message to write * @returns {void} */ public static debug(message: string): void { - Logger._handlers["debug"](message); + if(Logger.shouldLog(4)) Logger._handlers["debug"](message); } /** * Write a trace message to the console. * By default, only shows up when the "DEBUG" env is set to truthy. * + * Available in log levels 5 and higher. + * * @param message * @returns {void} */ public static trace(message: string): void { - Logger._handlers["trace"](message); + if(Logger.shouldLog(5)) Logger._handlers["trace"](message); } /** @@ -163,4 +175,14 @@ export class Logger { public static time(): string { return new Time().format(Configure.get("logger.timeformat", "yyyy/MM/dd HH:mm:ss")); } + + /** + * Check + * + * @param level + * @private + */ + private static shouldLog(level: number): boolean { + return Configure.get("log_level", 5) > level; + } } From 1751a7f1886ce3fced3f0a70515367b681a5c712 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 3 Jun 2025 13:40:08 +0200 Subject: [PATCH 303/379] Move some log levels around --- core/cache.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index b1320150..a1de5cd0 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -307,24 +307,24 @@ export class Cache { for (const [key, value] of Cache._items) { // Keep items that do not expire if (!value.expires) { - Logger.debug(`Keeping cache item "${key}": Does not expire`); + Logger.trace(`Keeping cache item "${key}": Does not expire`); continue; } // Keep items that have not yet expired if (value.expires >= now) { - Logger.debug(`Keeping cache item "${key}": Has not expired`); + Logger.trace(`Keeping cache item "${key}": Has not expired`); continue; } // Keep items that may be served optimistically if (value.optimistic && value.optimistic >= now) { - Logger.debug(`Keeping cache item "${key}": Keep for optimistic caching`); + Logger.trace(`Keeping cache item "${key}": Keep for optimistic caching`); continue; } // Clean up items that have expired - Logger.debug(`Removing expired cache item "${key}"`); + Logger.trace(`Removing expired cache item "${key}"`); Cache._items.delete(key); Cache._metrics.swept++; } From a46010d61aec27b1bb0adc86417a77ff65685639 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 3 Jun 2025 14:27:04 +0200 Subject: [PATCH 304/379] Fix bug with log levels not working properly --- core/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/logger.ts b/core/logger.ts index e6728216..6245e043 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -183,6 +183,6 @@ export class Logger { * @private */ private static shouldLog(level: number): boolean { - return Configure.get("log_level", 5) > level; + return Configure.get("log_level", 5) >= level; } } From 5b3c77af5935f772d517bb4e0ebe7a2f584cd446 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 17 Jun 2025 00:25:40 +0200 Subject: [PATCH 305/379] Change the way we define the type --- communication/couchdb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 97a9af55..d271a2ec 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -406,7 +406,7 @@ export class CouchDB { // Check if we have a 304 // If so, get data from cache - const cached = Cache.get(`chomp.couchdb.cache ${cacheKey}`) as CachedResponse + const cached = Cache.get(`chomp.couchdb.cache ${cacheKey}`); if(resp.status === 304 && cached) return cached.data; // Check whether we have an error From 2e2e3c7389164d14ba9fb34ea8c8735cf7138383 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 17 Jun 2025 00:34:04 +0200 Subject: [PATCH 306/379] Change the way we define the type --- communication/couchdb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index d271a2ec..1baa0c69 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -175,7 +175,7 @@ export class CouchDB { if(!cache) return this.raw(id); // Get the etag from cache - const cached = Cache.get(`chomp.couchdb.cache ${id}`) as CachedResponse|null; + const cached = Cache.get(`chomp.couchdb.cache ${id}`); // Check if cached version was found // If not, run the request without etag From 54c0b168280b5bd2e06f61153eaead67e504d05a Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 17 Jun 2025 00:39:24 +0200 Subject: [PATCH 307/379] Hopefully fix a race condition --- communication/couchdb.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 1baa0c69..85fa5b19 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -169,7 +169,7 @@ export class CouchDB { * @param id * @param cache */ - public get(id: string, cache: boolean = true): Promise { + public async get(id: string, cache: boolean = true): Promise { // Check if we want to cache // If not, just run the request without etag if(!cache) return this.raw(id); @@ -182,9 +182,16 @@ export class CouchDB { if(!cached) return this.raw(id); // Run the request with the etag - return this.raw(id, null, { + const [error, data, status] = await this.raw(id, null, { etag: cached.etag, }); + + // If we somehow have a 304 still, use the cached version we have already + // This can happen in rare cases where the existing entry expired while querying the database + if(status === 304) return cached.data; + + // Return our response object + return [error, data, status]; } /** From 47921b4984f332d2db19e286e1333f85b7d6c256 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 17 Jun 2025 00:50:59 +0200 Subject: [PATCH 308/379] Do not double-assign variable --- communication/couchdb.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 85fa5b19..2d7bcbe3 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -412,9 +412,8 @@ export class CouchDB { const resp = await fetch(`${this.host}/${this.database}${endpoint}`, opts); // Check if we have a 304 - // If so, get data from cache - const cached = Cache.get(`chomp.couchdb.cache ${cacheKey}`); - if(resp.status === 304 && cached) return cached.data; + // If so, return here + if(resp.status === 304) return [undefined, {_id: endpoint, _rev: overrides["etag"]}, 304]; // Check whether we have an error // If so, return From 79e92b5effe2b767b76a86ff3592ab3c012be538 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 14 Jul 2025 01:32:51 +0200 Subject: [PATCH 309/379] Add crude validation class --- validation/rules/is-empty.ts | 15 +++++++ validation/rules/is-null.ts | 6 +++ validation/rules/is-undefined.ts | 6 +++ validation/validator.ts | 67 ++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 validation/rules/is-empty.ts create mode 100644 validation/rules/is-null.ts create mode 100644 validation/rules/is-undefined.ts create mode 100644 validation/validator.ts diff --git a/validation/rules/is-empty.ts b/validation/rules/is-empty.ts new file mode 100644 index 00000000..93cec359 --- /dev/null +++ b/validation/rules/is-empty.ts @@ -0,0 +1,15 @@ +import {ValidationCallbackResponse} from "../validator.ts"; + +export function isEmpty(input: any, errorMessage?: string): ValidationCallbackResponse { +// Check if empty string + if(input === "") return [errorMessage]; + + // Check if empty array + if(Array.isArray(input) && input.length === 0) return [errorMessage]; + + // Check if empty object + if(typeof input === "object" && Object.keys(input).length === 0) return [errorMessage]; + + // We have something inside + return [undefined]; +} diff --git a/validation/rules/is-null.ts b/validation/rules/is-null.ts new file mode 100644 index 00000000..33adac5b --- /dev/null +++ b/validation/rules/is-null.ts @@ -0,0 +1,6 @@ +import {ValidationCallbackResponse} from "../validator.ts"; + +export function isNull(input: any, errorMessage?: string): ValidationCallbackResponse { + if(input !== null) return [errorMessage]; + return [undefined]; +} diff --git a/validation/rules/is-undefined.ts b/validation/rules/is-undefined.ts new file mode 100644 index 00000000..a5cddbd8 --- /dev/null +++ b/validation/rules/is-undefined.ts @@ -0,0 +1,6 @@ +import {ValidationCallbackResponse} from "../validator.ts"; + +export function isUndefined(input: any, errorMessage?: string): ValidationCallbackResponse { + if(input !== undefined) return [errorMessage]; + return [undefined]; +} diff --git a/validation/validator.ts b/validation/validator.ts new file mode 100644 index 00000000..32336779 --- /dev/null +++ b/validation/validator.ts @@ -0,0 +1,67 @@ +import { isEmpty } from "./rules/is-empty.ts"; +import { isNull } from "./rules/is-null.ts"; +import { isUndefined } from "./rules/is-undefined.ts"; +import {raise} from "../error/raise.ts"; + +export type ValidationCallbackResponse = ValidationCallbackSuccess|ValidationCallbackError; + +type ValidationStep = { + callback: ValidationCallback + errorMessage?: string; +}; +type ValidationCallback = (input: any) => ValidationCallbackResponse; +type ValidationCallbackSuccess = [undefined]; +type ValidationCallbackError = [string]; + +const ChompValidators = new Map([ + ['isEmpty', isEmpty], + ['isNull', isNull], + ['isUndefined', isUndefined], +]); + +/** + * Run validator functions on inputs. + * + * **NOTE**: This is currently still an alpha feature. + */ +export class Validator { + private _validators: ValidationStep[] = []; + + /** + * Add a validator step + * + * @param validator + * @param message + */ + public add(validator: ValidationCallback|string, message?: string) { + // Check if validator type is a string + // If so, check with built-ins + if(typeof validator === 'string') { + if(!ChompValidators.has(validator)) raise(`Validator "${validator}" was not found`, 'ValidatorNotFound'); + validator = ChompValidators.get(validator)!; + } + + // Add step to validators + this._validators.push({ + callback: validator, + errorMessage: message, + }); + + return this; + } + + /** + * Execute all validator steps + * + * @param input + */ + public execute(input: any) { + // Create array to collect validation errors + const errors = []; + + for(const validator of this._validators) { + const [error] = validator['callback'](input); + if(error) errors.push(error); + } + } +} From 8eeba0b05689e97c929998f72b1495284859c2b9 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 14 Jul 2025 01:36:45 +0200 Subject: [PATCH 310/379] Allow setting stopOnFailure and actually return the errors --- validation/validator.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/validation/validator.ts b/validation/validator.ts index 32336779..dad33a87 100644 --- a/validation/validator.ts +++ b/validation/validator.ts @@ -25,6 +25,7 @@ const ChompValidators = new Map([ * **NOTE**: This is currently still an alpha feature. */ export class Validator { + private _stopOnFailure: boolean = false; private _validators: ValidationStep[] = []; /** @@ -50,6 +51,14 @@ export class Validator { return this; } + /** + * Stop validation on the first failing rule instead of checking all possible rules. + */ + public setStopOnFailure() { + this._stopOnFailure = true; + return this; + } + /** * Execute all validator steps * @@ -59,9 +68,13 @@ export class Validator { // Create array to collect validation errors const errors = []; + // Execute all validators for(const validator of this._validators) { const [error] = validator['callback'](input); if(error) errors.push(error); + if(this._stopOnFailure && errors.length > 0) break; } + + return errors; } } From 9e3aff22f8ffcc10aec3ea59818c30a385c1e8cb Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 14 Jul 2025 10:11:21 +0200 Subject: [PATCH 311/379] Make some changes to validator --- validation/rules/is-empty.ts | 12 ++++----- validation/rules/is-null.ts | 6 ++--- validation/rules/is-undefined.ts | 8 +++--- validation/rules/max-length.ts | 7 ++++++ validation/rules/min-length.ts | 7 ++++++ validation/validator.ts | 43 ++++++++++++++++++++++++++------ 6 files changed, 62 insertions(+), 21 deletions(-) create mode 100644 validation/rules/max-length.ts create mode 100644 validation/rules/min-length.ts diff --git a/validation/rules/is-empty.ts b/validation/rules/is-empty.ts index 93cec359..e3561c76 100644 --- a/validation/rules/is-empty.ts +++ b/validation/rules/is-empty.ts @@ -1,14 +1,14 @@ -import {ValidationCallbackResponse} from "../validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; -export function isEmpty(input: any, errorMessage?: string): ValidationCallbackResponse { -// Check if empty string - if(input === "") return [errorMessage]; +export function isEmpty(input: any, options: ValidationOptions): ValidationCallbackResponse { + // Check if empty string + if(input === "") return [options.message]; // Check if empty array - if(Array.isArray(input) && input.length === 0) return [errorMessage]; + if(Array.isArray(input) && input.length === 0) return [options.message]; // Check if empty object - if(typeof input === "object" && Object.keys(input).length === 0) return [errorMessage]; + if(typeof input === "object" && Object.keys(input).length === 0) return [options.message]; // We have something inside return [undefined]; diff --git a/validation/rules/is-null.ts b/validation/rules/is-null.ts index 33adac5b..bdf1f98d 100644 --- a/validation/rules/is-null.ts +++ b/validation/rules/is-null.ts @@ -1,6 +1,6 @@ -import {ValidationCallbackResponse} from "../validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; -export function isNull(input: any, errorMessage?: string): ValidationCallbackResponse { - if(input !== null) return [errorMessage]; +export function isNull(input: any, options: ValidationOptions): ValidationCallbackResponse { + if(input === null) return [undefined]; return [undefined]; } diff --git a/validation/rules/is-undefined.ts b/validation/rules/is-undefined.ts index a5cddbd8..ab70e80d 100644 --- a/validation/rules/is-undefined.ts +++ b/validation/rules/is-undefined.ts @@ -1,6 +1,6 @@ -import {ValidationCallbackResponse} from "../validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; -export function isUndefined(input: any, errorMessage?: string): ValidationCallbackResponse { - if(input !== undefined) return [errorMessage]; - return [undefined]; +export function isUndefined(input: any, options: ValidationOptions): ValidationCallbackResponse { + if(input === undefined) return [undefined]; + return [options.message]; } diff --git a/validation/rules/max-length.ts b/validation/rules/max-length.ts new file mode 100644 index 00000000..fbdcc0b7 --- /dev/null +++ b/validation/rules/max-length.ts @@ -0,0 +1,7 @@ +import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; +import {valueOrDefault} from "../../utility/value-or-default.ts"; + +export function maxLength(input: any, options: ValidationOptions): ValidationCallbackResponse { + if(input.length < valueOrDefault(options.parameters?.length, 0)) return [undefined]; + return [options.message]; +} diff --git a/validation/rules/min-length.ts b/validation/rules/min-length.ts new file mode 100644 index 00000000..bf20b2fc --- /dev/null +++ b/validation/rules/min-length.ts @@ -0,0 +1,7 @@ +import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; +import {valueOrDefault} from "../../utility/value-or-default.ts"; + +export function minLength(input: any, options: ValidationOptions): ValidationCallbackResponse { + if(input.length >= valueOrDefault(options.parameters?.length, 0)) return [undefined]; + return [options.message]; +} diff --git a/validation/validator.ts b/validation/validator.ts index dad33a87..fd1210d1 100644 --- a/validation/validator.ts +++ b/validation/validator.ts @@ -2,21 +2,33 @@ import { isEmpty } from "./rules/is-empty.ts"; import { isNull } from "./rules/is-null.ts"; import { isUndefined } from "./rules/is-undefined.ts"; import {raise} from "../error/raise.ts"; +import {minLength} from "./rules/min-length.ts"; +import {maxLength} from "./rules/max-length.ts"; export type ValidationCallbackResponse = ValidationCallbackSuccess|ValidationCallbackError; +export type ValidationCallbackParameters = ValidationParameter[]; +export type ValidationOptions = { + last?: boolean; + message?: string; + parameters?: ValidationCallbackParameters; +}; type ValidationStep = { callback: ValidationCallback - errorMessage?: string; + options: ValidationOptions; }; -type ValidationCallback = (input: any) => ValidationCallbackResponse; +type ValidationCallback = (input: any, parameters: any) => ValidationCallbackResponse; type ValidationCallbackSuccess = [undefined]; type ValidationCallbackError = [string]; +type ValidationParameter = {[key: string]: any}; + const ChompValidators = new Map([ ['isEmpty', isEmpty], ['isNull', isNull], ['isUndefined', isUndefined], + ['minLength', minLength], + ['maxLength', maxLength], ]); /** @@ -32,9 +44,9 @@ export class Validator { * Add a validator step * * @param validator - * @param message + * @param options */ - public add(validator: ValidationCallback|string, message?: string) { + public add(validator: ValidationCallback|string, options: ValidationOptions = {}) { // Check if validator type is a string // If so, check with built-ins if(typeof validator === 'string') { @@ -42,10 +54,13 @@ export class Validator { validator = ChompValidators.get(validator)!; } + // Check if we need to enable the "last" options + if(this._stopOnFailure) options.last = true; + // Add step to validators this._validators.push({ callback: validator, - errorMessage: message, + options: options, }); return this; @@ -53,9 +68,16 @@ export class Validator { /** * Stop validation on the first failing rule instead of checking all possible rules. + * + * @param existing Whether to enable this for all existing rules */ - public setStopOnFailure() { + public setStopOnFailure(existing: boolean = false) { + // Enable "last" flag for all new rules this._stopOnFailure = true; + + // Enable "last" flag for existing rules if need be + if(existing) this._validators.forEach((step: ValidationStep) => step.options.last = true); + return this; } @@ -70,9 +92,14 @@ export class Validator { // Execute all validators for(const validator of this._validators) { - const [error] = validator['callback'](input); + // Execute validator + const [error] = validator['callback'](input, validator.options); + + // Add error to list if(error) errors.push(error); - if(this._stopOnFailure && errors.length > 0) break; + + // Check if we need to keep running + if(errors.length > 0 && validator['options'].last) break; } return errors; From 6638989558b366ad9b837b0d4f89308e30524c24 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 14 Jul 2025 10:18:20 +0200 Subject: [PATCH 312/379] Re-organize some code and add way for app to create (and overwrite) validators --- validation/rules.ts | 14 ++++++++++++++ validation/validator.ts | 30 +++++++++++++----------------- 2 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 validation/rules.ts diff --git a/validation/rules.ts b/validation/rules.ts new file mode 100644 index 00000000..7e78922e --- /dev/null +++ b/validation/rules.ts @@ -0,0 +1,14 @@ +import { ValidationCallback } from "./validator.ts"; +import { isEmpty } from "./rules/is-empty.ts"; +import { isNull } from "./rules/is-null.ts"; +import { isUndefined } from "./rules/is-undefined.ts"; +import {minLength} from "./rules/min-length.ts"; +import {maxLength} from "./rules/max-length.ts"; + +export const Validators = new Map([ + ['isEmpty', isEmpty], + ['isNull', isNull], + ['isUndefined', isUndefined], + ['minLength', minLength], + ['maxLength', maxLength], +]); diff --git a/validation/validator.ts b/validation/validator.ts index fd1210d1..151ad72e 100644 --- a/validation/validator.ts +++ b/validation/validator.ts @@ -1,10 +1,7 @@ -import { isEmpty } from "./rules/is-empty.ts"; -import { isNull } from "./rules/is-null.ts"; -import { isUndefined } from "./rules/is-undefined.ts"; import {raise} from "../error/raise.ts"; -import {minLength} from "./rules/min-length.ts"; -import {maxLength} from "./rules/max-length.ts"; +import { Validators } from "./rules.ts"; +export type ValidationCallback = (input: any, parameters: any) => ValidationCallbackResponse; export type ValidationCallbackResponse = ValidationCallbackSuccess|ValidationCallbackError; export type ValidationCallbackParameters = ValidationParameter[]; export type ValidationOptions = { @@ -17,20 +14,10 @@ type ValidationStep = { callback: ValidationCallback options: ValidationOptions; }; -type ValidationCallback = (input: any, parameters: any) => ValidationCallbackResponse; type ValidationCallbackSuccess = [undefined]; type ValidationCallbackError = [string]; type ValidationParameter = {[key: string]: any}; - -const ChompValidators = new Map([ - ['isEmpty', isEmpty], - ['isNull', isNull], - ['isUndefined', isUndefined], - ['minLength', minLength], - ['maxLength', maxLength], -]); - /** * Run validator functions on inputs. * @@ -40,6 +27,15 @@ export class Validator { private _stopOnFailure: boolean = false; private _validators: ValidationStep[] = []; + public create(name: string, validator: ValidationCallback, overwrite: boolean = false) { + // Check if a validator already exists + // Skip if we want to override + if(!overwrite && Validators.has(name)) raise(`Validator named "${name}" already exists!`); + + // Add validator + Validators.set(name, validator); + } + /** * Add a validator step * @@ -50,8 +46,8 @@ export class Validator { // Check if validator type is a string // If so, check with built-ins if(typeof validator === 'string') { - if(!ChompValidators.has(validator)) raise(`Validator "${validator}" was not found`, 'ValidatorNotFound'); - validator = ChompValidators.get(validator)!; + if(!Validators.has(validator)) raise(`Validator "${validator}" was not found`, 'ValidatorNotFound'); + validator = Validators.get(validator)!; } // Check if we need to enable the "last" options From a876829ef1a963e17796f8971b19999fc8f48cea Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 14 Jul 2025 10:49:42 +0200 Subject: [PATCH 313/379] Fix small bug in is-null --- validation/rules/is-null.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation/rules/is-null.ts b/validation/rules/is-null.ts index bdf1f98d..d2e44d65 100644 --- a/validation/rules/is-null.ts +++ b/validation/rules/is-null.ts @@ -2,5 +2,5 @@ import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; export function isNull(input: any, options: ValidationOptions): ValidationCallbackResponse { if(input === null) return [undefined]; - return [undefined]; + return [options.message]; } From 3091ad6aba3e82118e758969602b5a9891cd2a2c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 21 Jul 2025 08:28:35 +0200 Subject: [PATCH 314/379] Attempt at getting more accurate IP on webserver --- webserver/webserver.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/webserver/webserver.ts b/webserver/webserver.ts index bf66bf45..43c0a279 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -1,6 +1,8 @@ import { Logger } from "../core/logger.ts"; import { Router } from "./routing/router.ts"; import { StatusCodes } from "./http/status-codes.ts"; +import {valueOrDefault} from "../utility/value-or-default.ts"; +import {Configure} from "../core/configure.ts"; export class Webserver { private server: Deno.Listener | null = null; @@ -28,8 +30,13 @@ export class Webserver { // Handle each request for this connection for await (const request of httpConn) { + const clientIp = valueOrDefault( + request.request.headers.get(Configure.get("real_ip_header", "X-Forwarded-For")), + (conn.remoteAddr as Deno.NetAddr).hostname! + ); + Logger.debug( - `Request from "${(conn.remoteAddr as Deno.NetAddr).hostname!}:${(conn.remoteAddr as Deno.NetAddr) + `Request from "${clientIp}:${(conn.remoteAddr as Deno.NetAddr) .port!}": ${request.request.method} | ${request.request.url}`, ); try { From cb072d7235d870cd55ede926169402324bc47604 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Jul 2025 17:26:32 +0200 Subject: [PATCH 315/379] Allow writing to files --- filesystem/file.ts | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/filesystem/file.ts b/filesystem/file.ts index 47e6b3a3..17e3abdc 100644 --- a/filesystem/file.ts +++ b/filesystem/file.ts @@ -33,11 +33,29 @@ export class File { return this.path.slice(pos + 1); } - public async readTextFile() { - return await Deno.readTextFile(this.path); + public readTextFile() { + return Deno.readTextFile(this.path); } - public async readFile() { - return await Deno.readFile(this.path); + public readFile() { + return Deno.readFile(this.path); + } + + public async writeTextFile(data: string|ReadableStream, options?: Deno.WriteFileOptions) { + try { + await Deno.writeTextFile(this.path, data, options); + return true; + } catch(e) { + return false; + } + } + + public async writeFile(data: Uint8Array|ReadableStream, options?: Deno.WriteFileOptions) { + try { + await Deno.writeFile(this.path, data, options); + return true; + } catch(e) { + return false; + } } } From 0c406eab7cef76e30587e8858e21cd5b073a4143 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Jul 2025 17:30:10 +0200 Subject: [PATCH 316/379] Allow copying and moving files --- filesystem/file.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/filesystem/file.ts b/filesystem/file.ts index 17e3abdc..5ad93ee9 100644 --- a/filesystem/file.ts +++ b/filesystem/file.ts @@ -27,6 +27,24 @@ export class File { await Deno.remove(this.path); } + public async move(path: string): Promise { + try { + await Deno.rename(this.path, path); + return new File(path); + }catch(e) { + return false; + } + } + + public async copy(path: string): Promise { + try { + await Deno.copyFile(this.path, path); + return new File(path); + }catch(e) { + return false; + } + } + public ext(): string { const pos = this.path.lastIndexOf("."); if (pos < 1) return ""; From 385423600fdd2e128ecf7f134f72a6cc01d3ddc8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Jul 2025 17:32:37 +0200 Subject: [PATCH 317/379] Move create function in code --- filesystem/file.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/filesystem/file.ts b/filesystem/file.ts index 5ad93ee9..e9c2c6d0 100644 --- a/filesystem/file.ts +++ b/filesystem/file.ts @@ -9,10 +9,6 @@ export class File { ) { } - public async create(): Promise { - await Deno.create(this.path); - } - public async exists(): Promise { try { const target = await Deno.stat(this.path); @@ -23,6 +19,10 @@ export class File { } } + public async create(): Promise { + await Deno.create(this.path); + } + public async delete(): Promise { await Deno.remove(this.path); } From 75c55ac179baac8a9878e3bb43a6e4a666a8ab4d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Jul 2025 17:32:46 +0200 Subject: [PATCH 318/379] Add some return types --- filesystem/file.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/filesystem/file.ts b/filesystem/file.ts index e9c2c6d0..221c8837 100644 --- a/filesystem/file.ts +++ b/filesystem/file.ts @@ -51,15 +51,15 @@ export class File { return this.path.slice(pos + 1); } - public readTextFile() { + public readTextFile(): Promise { return Deno.readTextFile(this.path); } - public readFile() { + public readFile(): Promise { return Deno.readFile(this.path); } - public async writeTextFile(data: string|ReadableStream, options?: Deno.WriteFileOptions) { + public async writeTextFile(data: string|ReadableStream, options?: Deno.WriteFileOptions): Promise { try { await Deno.writeTextFile(this.path, data, options); return true; @@ -68,7 +68,7 @@ export class File { } } - public async writeFile(data: Uint8Array|ReadableStream, options?: Deno.WriteFileOptions) { + public async writeFile(data: Uint8Array|ReadableStream, options?: Deno.WriteFileOptions): Promise { try { await Deno.writeFile(this.path, data, options); return true; From c012305bd755877ff241d54dbc67a1e71235fa37 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Jul 2025 17:38:41 +0200 Subject: [PATCH 319/379] Use File class to load ConfigureAnd some logging changes --- core/configure.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/configure.ts b/core/configure.ts index 40708b88..28598dde 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,5 +1,6 @@ import { Logger } from "./logger.ts"; import {valueOrDefault} from "../utility/value-or-default.ts"; +import { File } from "../filesystem/file.ts"; // deno-lint-ignore no-explicit-any -- Arbitrary data may be used const defaults = new Map([ @@ -68,25 +69,27 @@ export class Configure { * @deprecated Switching to using solely TS-based configs */ private static async _loadJson() { + const file = new File(`${Deno.cwd()}/config.json`); + // Make sure our file exists - try { - await Deno.stat(`${Deno.cwd()}/config.json`); - } catch (_e) { + if(!await file.exists()) { Logger.warning(`Could not find file "config.json" at "${Deno.cwd()}". Configure will be empty!`); Configure.hasLoaded = true; return; } - // Read our JSON + // Read our JSON content + const json = await file.readTextFile(); + + // Parse JSON try { - const json = await Deno.readTextFile(`${Deno.cwd()}/config.json`); const data = JSON.parse(json); for (const entry of Object.keys(data)) { + Logger.debug(`Adding "${entry}" into Configure...`); Configure.set(entry, data[entry]); } } catch (e) { Logger.error(`Could not load JSON: "${e.message}"`, e.stack); - return; } } From f8378cfa43637d49138179d897688f7611f7ba77 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sat, 26 Jul 2025 17:40:22 +0200 Subject: [PATCH 320/379] Void promise --- core/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/logger.ts b/core/logger.ts index 6245e043..3c91cfe3 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -24,7 +24,7 @@ const handlers: Handlers = { try { let output = `[${now}] ERROR > ${message}`; if (stack) output += `\r\n${stack}`; - Deno.writeTextFile(Configure.get("error_log"), output, { append: true }); + void Deno.writeTextFile(Configure.get("error_log"), output, { append: true }); } catch (e) { console.error(`Could not append to error log: "${e.message}"`); } From 8f53ed53ed6e07cf941ab45048a6465791f4ca69 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 16 Sep 2025 13:45:32 +0200 Subject: [PATCH 321/379] Add extensions to make life easier --- README.md | 10 +++++++ extensions/bigint/to-json.ts | 16 ++++++++++ extensions/date/is-after-or-equal.ts | 17 +++++++++++ extensions/date/is-after.ts | 17 +++++++++++ extensions/date/is-before-or-equal.ts | 17 +++++++++++ extensions/date/is-before.ts | 17 +++++++++++ extensions/date/set-midnight.ts | 16 ++++++++++ tests/extensions/date.ts | 43 +++++++++++++++++++++++++++ 8 files changed, 153 insertions(+) create mode 100644 extensions/bigint/to-json.ts create mode 100644 extensions/date/is-after-or-equal.ts create mode 100644 extensions/date/is-after.ts create mode 100644 extensions/date/is-before-or-equal.ts create mode 100644 extensions/date/is-before.ts create mode 100644 extensions/date/set-midnight.ts create mode 100644 tests/extensions/date.ts diff --git a/README.md b/README.md index e5374cbb..f18e6903 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,16 @@ As a result, some things can be configured by you by adding entries to the Confi | `chomp_optimistic_delay` | `'+1 hour'` | Additional time a cache entry may exist for optimistic caching. Uses the `utility/time-string` formats | | `chomp_couchdb_cache` | `'+1 hour'` | Time a document for `communication/couchdb` will be kept in the cache to improve read times. Uses the `utility/time-string` formats | +### Extensions + +Chomp includes a few "extensions" that _modify JavaScript's built-in prototypes_. +Most of these should be free from interference unless you use other libraries that do this. +You can load extensions by simply including them into your project. + +```ts +import "https://deno.land/x/chomp/extensions/date/is-before.ts"; +``` + ## Versioning As of `?.0.0.0-0`, versioning adheres to the following versioning system of `a.b.c.d-e` where: diff --git a/extensions/bigint/to-json.ts b/extensions/bigint/to-json.ts new file mode 100644 index 00000000..b22cb320 --- /dev/null +++ b/extensions/bigint/to-json.ts @@ -0,0 +1,16 @@ +/** + * Add function to BigInt interface + */ +declare global { + interface BigInt { + toJSON(): string; + } +} + +/** + * Turn BigInt into String when turning it into JSON. + * (Why isn't this a thing in JS itself?) + */ +BigInt.prototype.toJSON = function () { + return this.toString(); +}; diff --git a/extensions/date/is-after-or-equal.ts b/extensions/date/is-after-or-equal.ts new file mode 100644 index 00000000..6a78c022 --- /dev/null +++ b/extensions/date/is-after-or-equal.ts @@ -0,0 +1,17 @@ +/** + * Add function to Date interface + */ +declare global { + interface Date { + isAfterOrEqual(date: Date): boolean; + } +} + +/** + * Check whether the date is after or equal to the input date. + * + * @param date + */ +Date.prototype.isAfterOrEqual = function(date: Date) { + return this.getTime() >= date.getTime(); +} diff --git a/extensions/date/is-after.ts b/extensions/date/is-after.ts new file mode 100644 index 00000000..a4552948 --- /dev/null +++ b/extensions/date/is-after.ts @@ -0,0 +1,17 @@ +/** + * Add function to Date interface + */ +declare global { + interface Date { + isAfter(date: Date): boolean; + } +} + +/** + * Check whether the date is after the input date. + * + * @param date + */ +Date.prototype.isAfter = function(date: Date) { + return this.getTime() > date.getTime(); +} diff --git a/extensions/date/is-before-or-equal.ts b/extensions/date/is-before-or-equal.ts new file mode 100644 index 00000000..77b19d37 --- /dev/null +++ b/extensions/date/is-before-or-equal.ts @@ -0,0 +1,17 @@ +/** + * Add function to Date interface + */ +declare global { + interface Date { + isBeforeOrEqual(date: Date): boolean; + } +} + +/** + * Check whether the date is before or equal to the input date. + * + * @param date + */ +Date.prototype.isBeforeOrEqual = function(date: Date) { + return date.getTime() >= this.getTime(); +} diff --git a/extensions/date/is-before.ts b/extensions/date/is-before.ts new file mode 100644 index 00000000..74fc16b4 --- /dev/null +++ b/extensions/date/is-before.ts @@ -0,0 +1,17 @@ +/** + * Add function to Date interface + */ +declare global { + interface Date { + isBefore(date: Date): boolean; + } +} + +/** + * Check whether the date is before the input date. + * + * @param date + */ +Date.prototype.isBefore = function(date: Date) { + return date.getTime() > this.getTime(); +} diff --git a/extensions/date/set-midnight.ts b/extensions/date/set-midnight.ts new file mode 100644 index 00000000..97e8418e --- /dev/null +++ b/extensions/date/set-midnight.ts @@ -0,0 +1,16 @@ +/** + * Add function to Date interface + */ +declare global { + interface Date { + setMidnight(): Date; + } +} + +/** + * Set the date to midnight (00:00:00.000) + */ +Date.prototype.setMidnight = function() { + this.setHours(0, 0, 0, 0); + return this; +} diff --git a/tests/extensions/date.ts b/tests/extensions/date.ts new file mode 100644 index 00000000..d2236fa5 --- /dev/null +++ b/tests/extensions/date.ts @@ -0,0 +1,43 @@ +import "../../extensions/date/is-after.ts"; +import "../../extensions/date/is-after-or-equal.ts"; +import "../../extensions/date/is-before.ts"; +import "../../extensions/date/is-before-or-equal.ts"; +import "../../extensions/date/set-midnight.ts"; +import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; + +Deno.test("Date Extensions Test", async (t) => { + const a = new Date(0); + const b = new Date(1); + const c = new Date('2025-09-16T12:13:56.123Z').setMidnight(); + + await t.step("isAfter", () => { + assertEquals(b.isAfter(a), true); + assertEquals(a.isAfter(b), false); + assertEquals(b.isAfter(b), false); + }); + + await t.step("isAfterOrEqual", () => { + assertEquals(b.isAfterOrEqual(a), true); + assertEquals(a.isAfterOrEqual(b), false); + assertEquals(b.isAfterOrEqual(b), true); + }); + + await t.step("isBefore", () => { + assertEquals(a.isBefore(b), true); + assertEquals(b.isBefore(a), false); + assertEquals(b.isBefore(b), false); + }); + + await t.step("isBeforeOrEqual", () => { + assertEquals(a.isBeforeOrEqual(b), true); + assertEquals(b.isBeforeOrEqual(a), false); + assertEquals(b.isBeforeOrEqual(b), true); + }); + + await t.step("setMidnight", () => { + assertEquals(c.getTime(), 1757973600000); + assertEquals(a.isBeforeOrEqual(b), true); + assertEquals(b.isBeforeOrEqual(a), false); + assertEquals(b.isBeforeOrEqual(b), true); + }); +}); From 3ff4a0f7e5baa5d2f5bf7da30672e2d7437d4e78 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 24 Sep 2025 15:33:23 +0200 Subject: [PATCH 322/379] Disable linting and format tests for now --- .github/workflows/test.yml | 52 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0eaed6e1..2143bab1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,32 +5,32 @@ on: pull_request: branches: [main] jobs: - chomp-format: - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v3 - with: - submodules: true - - name: Set up Deno - uses: denoland/setup-deno@v1 - with: - deno-version: "1.40.0" - - name: Check format - run: deno fmt --check - chomp-lint: - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v3 - with: - submodules: true - - name: Set up Deno - uses: denoland/setup-deno@v1 - with: - deno-version: "1.40.0" - - name: Check lint - run: deno lint + #chomp-format: + # runs-on: ubuntu-latest + # steps: + # - name: Clone repository + # uses: actions/checkout@v3 + # with: + # submodules: true + # - name: Set up Deno + # uses: denoland/setup-deno@v1 + # with: + # deno-version: "1.40.0" + # - name: Check format + # run: deno fmt --check + #chomp-lint: + # runs-on: ubuntu-latest + # steps: + # - name: Clone repository + # uses: actions/checkout@v3 + # with: + # submodules: true + # - name: Set up Deno + # uses: denoland/setup-deno@v1 + # with: + # deno-version: "1.40.0" + # - name: Check lint + # run: deno lint chomp-tests: runs-on: ubuntu-latest steps: From 7f998929a3377d452b6ba4df5d2cd1434cd5c4f8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 25 Sep 2025 13:15:54 +0200 Subject: [PATCH 323/379] Create more globally usable Registry --- utility/registry.ts | 49 ++++++++++++++++++++++++++++++ webserver/controller/controller.ts | 2 +- webserver/registry/registry.ts | 3 ++ webserver/routing/router.ts | 2 +- 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 utility/registry.ts diff --git a/utility/registry.ts b/utility/registry.ts new file mode 100644 index 00000000..5aa31608 --- /dev/null +++ b/utility/registry.ts @@ -0,0 +1,49 @@ +import {valueOrDefault} from "./value-or-default.ts"; + +export class Registry { + private static readonly _items: Map = new Map(); + + /** + * Add an item to the registry + * + * @example Basic usage + * ```ts + * const module = await import(`file://path/to/my/file.ts`); + * Registry.add('my-module', module); + * ``` + * + * @param name + * @param module + */ + public static add(name: string, module: any): void { + Registry._items.set(name, module); + } + + /** + * Get an item from the registry + * + * @example Basic usage + * ```ts + * const module = Registry.add('my-module'); + * ``` + * + * @param name + */ + public static get(name: string): any | null { + return valueOrDefault(Registry._items.get(name), null); + } + + /** + * Check whether the registry has an item with name + * + * @example Basic usage + * ```ts + * const hasModule = Registry.has('my-module'); + * ``` + * + * @param name + */ + public static has(name: string): boolean { + return Registry._items.has(name); + } +} diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index cc48ba8b..58315ae8 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -5,7 +5,7 @@ import { ResponseBuilder } from "../http/response-builder.ts"; import { Request } from "../http/request.ts"; import { raise } from "../../error/raise.ts"; import { Component } from "./component.ts"; -import { Registry } from "../registry/registry.ts"; +import { Registry } from "../../utility/registry.ts"; import { compress as compressBrotli } from "https://deno.land/x/brotli@v0.1.4/mod.ts"; export interface ViewVariable { diff --git a/webserver/registry/registry.ts b/webserver/registry/registry.ts index 2e80affa..999e76b7 100644 --- a/webserver/registry/registry.ts +++ b/webserver/registry/registry.ts @@ -2,6 +2,9 @@ interface RegistryItem { [key: string]: any; } +/** + * @deprecated Use {@linkcode ../../utility/Registry} instead + */ export class Registry { private static _items: RegistryItem = {}; diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index 17886c67..dd0b04f3 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -7,7 +7,7 @@ import { QueryParameters, Request as ChompRequest, RequestParameters } from "../ import { StatusCodes } from "../http/status-codes.ts"; import { Route as ChompRoute } from "./route.ts"; import { Controller } from "../controller/controller.ts"; -import { Registry } from "../registry/registry.ts"; +import { Registry } from "../../utility/registry.ts"; import { raise } from "../../error/raise.ts"; interface Route { From 82a77a091e84bc945c9f7c1771b1ca379ea0706c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 13 Oct 2025 15:23:54 +0200 Subject: [PATCH 324/379] Add success log --- core/logger.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/logger.ts b/core/logger.ts index 3c91cfe3..0346cdef 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -4,6 +4,7 @@ import { bold, cyan, magenta, red, yellow, blue, green, gray } from "https://den type Handlers = { error: (message: string, stack: string | null) => void; + success: (message: string) => void; warning: (message: string) => void; notice: (message: string) => void; info: (message: string) => void; @@ -35,6 +36,9 @@ const handlers: Handlers = { if (stack) output += `\r\n${stack}`; console.error(output); }, + success: (message: string): void => { + console.log(`${Logger.time()} ${green("SUCCESS")} > ${message}`); + }, warning: (message: string): void => { console.error(`[${Logger.time()}] ${yellow("WARN")} > ${message}`); }, @@ -90,6 +94,18 @@ export class Logger { Logger._handlers["error"](message, stack); } + /** + * Write a success message to the console. + * + * Available in any log level. + * + * @param {string} message The message to write + * @returns {void} + */ + public static success(message: string): void { + Logger._handlers["success"](message); + } + /** * Write a warning message to the console * From f42ce77ed7a646401030dffcb374627269ce4dc5 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 13 Oct 2025 15:25:13 +0200 Subject: [PATCH 325/379] Fix formatting --- core/logger.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/logger.ts b/core/logger.ts index 0346cdef..9fba923b 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -32,33 +32,33 @@ const handlers: Handlers = { } // Write to console - let output = `[${now}] ${red(bold("ERROR"))} > ${message}`; + let output = `[${now}] ${red(bold("ERROR"))} > ${message}`; if (stack) output += `\r\n${stack}`; console.error(output); }, success: (message: string): void => { - console.log(`${Logger.time()} ${green("SUCCESS")} > ${message}`); + console.log(`[${Logger.time()}] ${green("SUCCESS")} > ${message}`); }, warning: (message: string): void => { - console.error(`[${Logger.time()}] ${yellow("WARN")} > ${message}`); + console.error(`[${Logger.time()}] ${yellow("WARN")} > ${message}`); }, notice: (message: string): void => { - console.error(`[${Logger.time()}] ${blue("NOTICE")} > ${message}`); + console.error(`[${Logger.time()}] ${blue("NOTICE")} > ${message}`); }, info: (message: string): void => { - console.log(`[${Logger.time()}] ${cyan("INFO")} > ${message}`); + console.log(`[${Logger.time()}] ${cyan("INFO")} > ${message}`); }, monitor: (message: string): void => { - console.log(`[${Logger.time()}] ${green("MONIT")} > ${message}`); + console.log(`[${Logger.time()}] ${green("MONIT")} > ${message}`); }, debug: (message: string): void => { if (Configure.get("debug", false)) { - console.log(`[${Logger.time()}] ${magenta("DEBUG")} > ${message}`); + console.log(`[${Logger.time()}] ${magenta("DEBUG")} > ${message}`); } }, trace: (message: string): void => { if (Configure.get("debug", false)) { - console.log(`[${Logger.time()}] ${gray("TRACE")} > ${message}`); + console.log(`[${Logger.time()}] ${gray("TRACE")} > ${message}`); } } }; From 4ae9b0fe95822b74a1d2006d1d585f489a0fb6b0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 14 Oct 2025 21:09:36 +0200 Subject: [PATCH 326/379] Fix issue hen error log doesn't exist and isn't set --- core/logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/logger.ts b/core/logger.ts index 9fba923b..1d6addf2 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -21,7 +21,7 @@ const handlers: Handlers = { // Check if we need to write to file // Write to file if need be - if (Configure.get("error_log")) { + if (Configure.get("error_log", false)) { try { let output = `[${now}] ERROR > ${message}`; if (stack) output += `\r\n${stack}`; From 270e1a90a0ac006f59736202a1cf2c8016879bc0 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 14 Oct 2025 23:50:22 +0200 Subject: [PATCH 327/379] Add argument parser utility --- utility/parse-arguments.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 utility/parse-arguments.ts diff --git a/utility/parse-arguments.ts b/utility/parse-arguments.ts new file mode 100644 index 00000000..3999993c --- /dev/null +++ b/utility/parse-arguments.ts @@ -0,0 +1,5 @@ +import { parseArgs, ParseOptions } from "jsr:@std/cli@1.0.23/parse-args"; + +export function parseArguments(options: ParseOptions = {}) { + return parseArgs(Deno.args, options); +} From 3b6760a62d1e0d87e20232b880675e7faa32c0d6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 11 Nov 2025 01:33:53 +0100 Subject: [PATCH 328/379] Update contracts to assert --- utility/contract.ts | 46 +++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/utility/contract.ts b/utility/contract.ts index 10895e53..f017b1fd 100644 --- a/utility/contract.ts +++ b/utility/contract.ts @@ -6,7 +6,7 @@ import { nameOf } from "./name-of.ts"; * Class to more easily throw errors while creating (among others) constructors. * Allows code to be more concise and users to more easily read what it does. * - * It was based on the .NET 6 feature of the same name. + * Its idea was based on the .NET 6 feature of the same name. */ export class Contract { /** @@ -35,23 +35,14 @@ export class Contract { * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; * * const myArgument = "blabla"; - * Contract.requireNotNull(myArgument, "myArgument"); - * ``` - * - * @example Using the {@linkcode nameOf} utility - * ```ts - * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; - * import { nameOf } from "https://deno.land/x/chomp/utility/name-of.ts"; - * - * const myArgument = "blabla"; - * Contract.requireNotNull(myArgument, nameOf({ myArgument })); + * Contract.requireNotNull(myArgument); * ``` * * @param argument - * @param argumentName + * @param message */ - public static requireNotNull(argument: unknown, argumentName: string): void|never { - if (argument === null) raise(`${argumentName} may not be null`, "ContractArgumentNull"); + public static requireNotNull(argument: T, message?: string): asserts argument is Exclude { + if (argument === null) raise(message ? message : `Contract failed, argument ("${argument}") was null`, "ContractArgumentNull"); } /** @@ -62,29 +53,40 @@ export class Contract { * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; * * const myArgument = "blabla"; - * Contract.requireNotUndefined(myArgument, "myArgument"); + * Contract.requireNotUndefined(myArgument); * ``` * - * @example Using the {@linkcode nameOf} utility + * @param argument + * @param message + */ + public static requireNotUndefined(argument: T, message?: string): asserts argument is Exclude { + if(argument === undefined) raise(message ? message : `Contract failed, argument ("${argument}") was undefined`, "ContractArgumentUndefined"); + } + + /** + * Require the input to not be nullish. + * + * Internally acts as a proxy for {@linkcode Contract.requireNotUndefined} and {@linkcode Contract.requireNotNull}. + * + * @example Basic Usage * ```ts * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; - * import { nameOf } from "https://deno.land/x/chomp/utility/name-of.ts"; * * const myArgument = "blabla"; - * Contract.requireNotUndefined(myArgument, nameOf({ myArgument })); + * Contract.requireNotNullish(myArgument); * ``` * * @param argument - * @param argumentName + * @param message */ - public static requireNotUndefined(argument: unknown, argumentName: string): void|never { - if(argument === undefined) raise(`${argumentName} may not be undefined`, "ContractArgumentUndefined"); + public static requireNotNullish(argument: T, message?: string): asserts argument is Exclude, undefined> { + Contract.requireNotUndefined(argument, message); + Contract.requireNotNull(argument, message); } /** * Require the input argument to not be empty * - * * @param argument */ public static requireNotEmpty(argument: unknown): void|never { From 87c2a30d529c15cad8c7810bbefc42fd87635494 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 11 Nov 2025 10:30:43 +0100 Subject: [PATCH 329/379] Add more generics --- utility/contract.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utility/contract.ts b/utility/contract.ts index f017b1fd..b3044b1c 100644 --- a/utility/contract.ts +++ b/utility/contract.ts @@ -89,7 +89,7 @@ export class Contract { * * @param argument */ - public static requireNotEmpty(argument: unknown): void|never { + public static requireNotEmpty(argument: T): void|never { if(empty(argument)) raise(`${nameOf({ argument })} may not be empty`, "ContractArgumentEmpty") } @@ -99,7 +99,7 @@ export class Contract { * * @param argument */ - public static requireEmpty(argument: unknown): void|never { + public static requireEmpty(argument: T): void|never { if(!empty(argument)) raise(`${nameOf({ argument })} must be empty`, "ContractArgumentNotEmpty"); } } From 8e694866a12497fe0248108268624680b45ef819 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 11 Nov 2025 10:32:59 +0100 Subject: [PATCH 330/379] Update tests --- tests/util/contract.test.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/util/contract.test.ts b/tests/util/contract.test.ts index eff1fd75..4c75aa66 100644 --- a/tests/util/contract.test.ts +++ b/tests/util/contract.test.ts @@ -12,18 +12,27 @@ Deno.test("Contract Test", async (t) => { await t.step("requireNotNull", () => { // Test when the argument is null - assertThrows(() => Contract.requireNotNull(null, "testArgument")); + assertThrows(() => Contract.requireNotNull(null)); // Test when the argument is not null - assert(() => Contract.requireNotNull("blabla", "testArgument")); + assert(() => Contract.requireNotNull("blabla")); }); await t.step("requireNotUndefined", () => { // Test when the argument is undefined - assertThrows(() => Contract.requireNotUndefined(undefined, "testArgument")); + assertThrows(() => Contract.requireNotUndefined(undefined)); // Test when the argument is not undefined - assert(() => Contract.requireNotUndefined("blabla", "testArgument")); + assert(() => Contract.requireNotUndefined("blabla")); + }); + + await t.step("requireNotNullish", () => { + // Test when argument is nullish + assertThrows(() => Contract.requireNotNullish(null)); + assertThrows(() => Contract.requireNotNullish(undefined)); + + // Test when argument is not nullish + assert(() => Contract.requireNotNullish("blabla")); }); await t.step("requireNotEmpty", () => { From 4d5149349daaa003991b9bfc37138b551cfde0c8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 11 Nov 2025 13:41:44 +0100 Subject: [PATCH 331/379] Add empty string extension --- extensions/string/empty.ts | 13 +++++++++++++ tests/extensions/string.test.ts | 9 +++++++++ 2 files changed, 22 insertions(+) create mode 100644 extensions/string/empty.ts create mode 100644 tests/extensions/string.test.ts diff --git a/extensions/string/empty.ts b/extensions/string/empty.ts new file mode 100644 index 00000000..9789f5da --- /dev/null +++ b/extensions/string/empty.ts @@ -0,0 +1,13 @@ +/** + * Add function to String interface + */ +declare global { + interface StringConstructor { + empty: string; + } +} + +/** + * Add empty type + */ +String.empty = ""; diff --git a/tests/extensions/string.test.ts b/tests/extensions/string.test.ts new file mode 100644 index 00000000..8ee6c795 --- /dev/null +++ b/tests/extensions/string.test.ts @@ -0,0 +1,9 @@ +import "../../extensions/string/empty.ts"; +import {assertEquals} from "https://deno.land/std@0.152.0/testing/asserts.ts"; + +Deno.test("String Extensions", async (t) => { + await t.step("Empty", () => { + assertEquals(String.empty === "", true); + assertEquals(String.empty === "foo", false); + }); +}); From 8e34adcbd2475b47cb614933efc2403b2dc7714c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 11 Nov 2025 13:42:08 +0100 Subject: [PATCH 332/379] Rename date extensions test --- tests/extensions/{date.ts => date.test.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/extensions/{date.ts => date.test.ts} (100%) diff --git a/tests/extensions/date.ts b/tests/extensions/date.test.ts similarity index 100% rename from tests/extensions/date.ts rename to tests/extensions/date.test.ts From f9bb83b47efd516ccb0002b6a7deb7461701fb46 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 11 Nov 2025 13:51:45 +0100 Subject: [PATCH 333/379] Add includesAny array extension --- extensions/array/includes-any.ts | 12 ++++++++++++ tests/extensions/array.test.ts | 13 +++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 extensions/array/includes-any.ts create mode 100644 tests/extensions/array.test.ts diff --git a/extensions/array/includes-any.ts b/extensions/array/includes-any.ts new file mode 100644 index 00000000..f5c293d7 --- /dev/null +++ b/extensions/array/includes-any.ts @@ -0,0 +1,12 @@ +/** + * Add function to Array interface + */ +declare global { + interface Array { + includesAny: (compareTo: T[]) => boolean; + } +} + +Array.prototype.includesAny = function(compareTo: T[]) { + return compareTo.some((value: T) => this.includes(value)); +} diff --git a/tests/extensions/array.test.ts b/tests/extensions/array.test.ts new file mode 100644 index 00000000..a420fec9 --- /dev/null +++ b/tests/extensions/array.test.ts @@ -0,0 +1,13 @@ +import "../../extensions/array/includes-any.ts"; +import {assertEquals} from "https://deno.land/std@0.152.0/testing/asserts.ts"; + +Deno.test("Array Extensions", async (t) => { + await t.step("includesAny", () => { + const a = [1,2,3,4]; + const b = [2, 5]; + const c = [5, 6]; + + assertEquals(a.includesAny(b), true); + assertEquals(a.includesAny(c), false); + }); +}); From fb7880178b39b718676a56ed5d80a8ab79429e19 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Nov 2025 19:25:48 +0100 Subject: [PATCH 334/379] Rewrite Queue to allow people to bring in their own schedulers more easily --- queue/queue.ts | 66 +++++-------------- queue/scheduler/first-in-first-out.ts | 12 ++++ queue/scheduler/last-in-first-out.ts | 12 ++++ .../scheduler/weighted-first-in-first-out.ts | 22 +++++++ tests/queue/queue.test.ts | 14 ++-- 5 files changed, 70 insertions(+), 56 deletions(-) create mode 100644 queue/scheduler/first-in-first-out.ts create mode 100644 queue/scheduler/last-in-first-out.ts create mode 100644 queue/scheduler/weighted-first-in-first-out.ts diff --git a/queue/queue.ts b/queue/queue.ts index 205cf5a1..9b8f6b93 100644 --- a/queue/queue.ts +++ b/queue/queue.ts @@ -1,21 +1,20 @@ -import { Logger } from "../core/logger.ts"; +import { default as defaultScheduler } from "./scheduler/first-in-first-out.ts"; -interface QueueItem { +export type QueueItem = { + /** + * Weight for the item. + * Only used in weighted algorithms. + */ weight?: number; + + /** + * Main data for the QueueItem + */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used data: any; } -export enum Scheduler { - /* First In, First Out */ - FIFO = 0, - - /* Last In, First Out */ - LIFO = 1, - - /* Highest Weight go out FIFO */ - WEIGHTED = 2, -} +export type Scheduler = (item: QueueItem, items: QueueItem[]) => QueueItem[]; /** * Crude yet effective in-memory Queue system @@ -24,7 +23,7 @@ export class Queue { private items: QueueItem[] = []; private readonly scheduler: Scheduler; - public constructor(scheduler: Scheduler = Scheduler.FIFO) { + public constructor(scheduler: Scheduler = defaultScheduler) { this.scheduler = scheduler; } @@ -85,7 +84,7 @@ export class Queue { } /** - * Add an item to the queue based on the scheduler used + * Add an item to the queue * * @param item Item to add to the queue */ @@ -93,43 +92,8 @@ export class Queue { // Make sure data was set if (Object.keys(item.data).length === 0) throw Error("Data for queue item may not be empty!"); - // Add item to the queue based on the scheduler used - switch (this.scheduler) { - case Scheduler.FIFO: - if ("weight" in item) { - Logger.debug("A weight was set without the weighted scheduler, removing it..."); - delete item.weight; - } - this.items.push(item); - break; - case Scheduler.LIFO: - if ("weight" in item) { - Logger.debug("A weight was set without the weighted scheduler, removing it..."); - delete item.weight; - } - this.items.unshift(item); - break; - case Scheduler.WEIGHTED: - if (!("weight" in item)) { - Logger.debug("No weight was set with weighted scheduler, defaulting to 0..."); - item.weight = 0; - } - - // Loop over all items in queue, add it at the bottom of it's weight - for (let i = 0; i < this.items.length; i++) { - // @ts-ignore Weight is set to 0 by default - if (item.weight > this.items[i].weight || i === this.items.length) { - this.items.splice(i, 0, item); - return; - } - } - - // Queue is empty, just push - this.items.push(item); - break; - default: - throw Error("No scheduler has been set, this is a bug!"); - } + // Add item to the queue via the scheduler + this.items = this.scheduler(item, this.items); } /** diff --git a/queue/scheduler/first-in-first-out.ts b/queue/scheduler/first-in-first-out.ts new file mode 100644 index 00000000..1fcafb83 --- /dev/null +++ b/queue/scheduler/first-in-first-out.ts @@ -0,0 +1,12 @@ +import {QueueItem} from "../queue.ts"; + +export default function(item: QueueItem, items: QueueItem[] = []) { + // Remove weight if specified + if ("weight" in item) delete item.weight; + + // Add item to the queue + items.push(item); + + // Return the queue + return items; +} diff --git a/queue/scheduler/last-in-first-out.ts b/queue/scheduler/last-in-first-out.ts new file mode 100644 index 00000000..be7bff5b --- /dev/null +++ b/queue/scheduler/last-in-first-out.ts @@ -0,0 +1,12 @@ +import {QueueItem} from "../queue.ts"; + +export default function(item: QueueItem, items: QueueItem[] = []) { + // Remove weight if specified + if ("weight" in item) delete item.weight; + + // Add item to the queue + items.unshift(item); + + // Return the queue + return items; +} diff --git a/queue/scheduler/weighted-first-in-first-out.ts b/queue/scheduler/weighted-first-in-first-out.ts new file mode 100644 index 00000000..b055587b --- /dev/null +++ b/queue/scheduler/weighted-first-in-first-out.ts @@ -0,0 +1,22 @@ +import {QueueItem} from "../queue.ts"; +import {valueOrDefault} from "../../utility/value-or-default.ts"; + +export default function(item: QueueItem, items: QueueItem[] = []) { + // Check if weight was set, otherwise default to 0 + item.weight = valueOrDefault(item.weight, 0); + + // Loop over all items in queue, add it at the bottom of it's weight + for (let i = 0; i < items.length; i++) { + // @ts-ignore Weight is set to 0 by default + if (item.weight > items[i].weight || i === items.length) { + items.splice(i, 0, item); + return items; + } + } + + // Add item to the queue + items.push(item); + + // Return the queue + return items; +} diff --git a/tests/queue/queue.test.ts b/tests/queue/queue.test.ts index 47a481d3..97b52bf3 100644 --- a/tests/queue/queue.test.ts +++ b/tests/queue/queue.test.ts @@ -1,10 +1,13 @@ import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { Queue, Scheduler } from "../../queue/queue.ts"; +import { Queue } from "../../queue/queue.ts"; +import { default as fifo } from "../../queue/scheduler/first-in-first-out.ts"; +import { default as lifo } from "../../queue/scheduler/last-in-first-out.ts"; +import { default as wfifo } from "../../queue/scheduler/weighted-first-in-first-out.ts"; Deno.test("Queue Test", async (t) => { await t.step("Common", () => { // Create our queue - const queue = new Queue(Scheduler.FIFO); + const queue = new Queue(fifo); // Test isEmpty and count without items assertEquals(queue.isEmpty, true); @@ -32,7 +35,7 @@ Deno.test("Queue Test", async (t) => { await t.step("FIFO Scheduler", () => { // Create our queue - const queue = new Queue(Scheduler.FIFO); + const queue = new Queue(fifo); // Add test items to the queue queue.add({ data: { job: "test1" } }); @@ -57,7 +60,7 @@ Deno.test("Queue Test", async (t) => { await t.step("LIFO Scheduler", () => { // Create our queue - const queue = new Queue(Scheduler.LIFO); + const queue = new Queue(lifo); // Add test items to the queue queue.add({ data: { job: "test1" } }); @@ -82,7 +85,7 @@ Deno.test("Queue Test", async (t) => { await t.step("WEIGHTED Scheduler", () => { // Create our queue - const queue = new Queue(Scheduler.WEIGHTED); + const queue = new Queue(wfifo); // Add test items to the queue queue.add({ weight: 0, data: { job: "test1" } }); @@ -93,6 +96,7 @@ Deno.test("Queue Test", async (t) => { queue.add({ data: { job: "test6" } }); // Make sure peeking works without removal + console.log(queue.dump); assertEquals(queue.peek, { weight: 3, data: { job: "test5" } }); assertEquals(queue.count, 6); From c6a73264961bc7ee9c8e00a5ced79df65aa0ee20 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Nov 2025 19:27:03 +0100 Subject: [PATCH 335/379] Remove console log --- tests/queue/queue.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/queue/queue.test.ts b/tests/queue/queue.test.ts index 97b52bf3..a1e393fe 100644 --- a/tests/queue/queue.test.ts +++ b/tests/queue/queue.test.ts @@ -96,7 +96,6 @@ Deno.test("Queue Test", async (t) => { queue.add({ data: { job: "test6" } }); // Make sure peeking works without removal - console.log(queue.dump); assertEquals(queue.peek, { weight: 3, data: { job: "test5" } }); assertEquals(queue.count, 6); From 276f88d0e651c7b8b19953469ff125a1d3de55d4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 20 Nov 2025 19:36:35 +0100 Subject: [PATCH 336/379] Refactor some contracts --- tests/util/contract.test.ts | 6 +++--- utility/contract.ts | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/tests/util/contract.test.ts b/tests/util/contract.test.ts index 4c75aa66..dfe1b142 100644 --- a/tests/util/contract.test.ts +++ b/tests/util/contract.test.ts @@ -2,12 +2,12 @@ import { Contract } from "../../utility/contract.ts"; import { assert, assertThrows } from "https://deno.land/std@0.152.0/testing/asserts.ts"; Deno.test("Contract Test", async (t) => { - await t.step("require", () => { + await t.step("requireCondition", () => { // Test when the condition is false - assertThrows(() => Contract.require(false, "Condition must be true")); + assertThrows(() => Contract.requireCondition(false, "Condition must be true")); // Test when the condition if true - assert(() => Contract.require(true, "Condition must be true")); + assert(() => Contract.requireCondition(true, "Condition must be true")); }); await t.step("requireNotNull", () => { diff --git a/utility/contract.ts b/utility/contract.ts index b3044b1c..58efa107 100644 --- a/utility/contract.ts +++ b/utility/contract.ts @@ -1,6 +1,7 @@ import { raise } from "../error/raise.ts"; import { empty } from "./empty.ts"; import { nameOf } from "./name-of.ts"; +import {valueOrDefault} from "./value-or-default.ts"; /** * Class to more easily throw errors while creating (among others) constructors. @@ -17,14 +18,24 @@ export class Contract { * import { Contract } from "https://deno.land/x/chomp/utility/contract.ts"; * * const myStatement = false; - * Contract.require(myStatement, "Statement must be true"); + * Contract.requireCondition(myStatement, "Statement must be true"); * ``` * * @param condition * @param message */ - public static require(condition: boolean, message: string): void|never { - if (!condition) raise(message, "ContractRequirementFalse"); + public static requireCondition(condition: boolean, message?: string): asserts condition is true { + if (!condition) raise( + valueOrDefault(message, 'Contract failed, passed condition was null'), + "ContractConditionFailed" + ); + } + + public static requireAssertion(argument: unknown, expression: boolean, message?: string): asserts argument is T { + if (!expression) raise("Expression evaluated to false"); + + Contract.requireNotNullish(argument, message); + Contract.requireNotNullish(expression, message); } /** @@ -42,7 +53,10 @@ export class Contract { * @param message */ public static requireNotNull(argument: T, message?: string): asserts argument is Exclude { - if (argument === null) raise(message ? message : `Contract failed, argument ("${argument}") was null`, "ContractArgumentNull"); + if (argument === null) raise( + valueOrDefault(message,`Contract failed, argument ("${argument}") was null`), + "ContractArgumentNull" + ); } /** From 9f3033ade1efcbaaf4aa90b44b72b1da56a05c98 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 26 Nov 2025 23:39:53 +0100 Subject: [PATCH 337/379] Add semi-colon --- tests/util/contract.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/util/contract.test.ts b/tests/util/contract.test.ts index dfe1b142..f780412f 100644 --- a/tests/util/contract.test.ts +++ b/tests/util/contract.test.ts @@ -63,5 +63,5 @@ Deno.test("Contract Test", async (t) => { assert(() => Contract.requireEmpty("")); assert(() => Contract.requireEmpty([])); assert(() => Contract.requireEmpty({})); - }) + }); }); From e24001f39c2f922ccad6267ba0c4554d4545ff0f Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 26 Nov 2025 23:40:18 +0100 Subject: [PATCH 338/379] Add Contract.requireUnreachable --- utility/contract.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/utility/contract.ts b/utility/contract.ts index 58efa107..f60a2d3d 100644 --- a/utility/contract.ts +++ b/utility/contract.ts @@ -116,4 +116,32 @@ export class Contract { public static requireEmpty(argument: T): void|never { if(!empty(argument)) raise(`${nameOf({ argument })} must be empty`, "ContractArgumentNotEmpty"); } + + /** + * Require this call to never be reached. + * Used for enforcing exhaustiveness. + * + * @example Basic usage + * ``` + * type Shape = + * | { kind: "circle"; radius: number; } + * | { kind: "square"; size: number; } + * + * function getArea(shape: Shape): number { + * switch(shape.kind) { + * case "circle": + * return Math.PI * shape.radius ** 2; + * case "square": + * return shape.size ** 2; + * default: + * Contract.requireUnreachable(shape); + * } + * } + * ``` + * + * @param argument + */ + public static requireUnreachable(argument: never): void { + raise(`Case not handled: ${argument}`); + } } From 4b331093c94d106800e382a503519210954551c7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Nov 2025 00:31:44 +0100 Subject: [PATCH 339/379] Significantly rewrite caching --- core/cache.ts | 66 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/core/cache.ts b/core/cache.ts index a1de5cd0..6be0a4e0 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -1,7 +1,7 @@ import { TimeString } from "../utility/time-string.ts"; import { Logger } from "./logger.ts"; -import { Cron } from "../utility/cron.ts"; import { Configure } from "./configure.ts"; +import {Contract} from "../utility/contract.ts"; interface CacheItem { // deno-lint-ignore no-explicit-any -- Any arbitrary data may be added to cache @@ -58,7 +58,7 @@ export class Cache { * * @param key */ - public static metrics(key: keyof CacheMetrics["reads"]|"rate"|"total"|"writes"|"swept"|"size"|null = null): number|CacheMetrics { + public static metrics(key: keyof CacheMetrics["reads"]|"rate"|"total"|"writes"|"swept"|"size"|null = null): T|number|CacheMetrics { switch(key) { case "hit": return Cache._metrics.reads.hit; @@ -105,17 +105,23 @@ export class Cache { public static set(key: string, value: any, expiry: string | null = "+1 minute"): void { let expiresAt = null; let optimisticExpiry = undefined; - if (expiry) { + + // Check if an expiry is specified + // Calculate the expiry values if so + if (expiry !== null) { const now = new Date(); expiresAt = new Date(now.getTime() + TimeString`${expiry}`); optimisticExpiry = new Date(expiresAt.getTime() + TimeString`${Configure.get('chomp_optimistic_delay', OPTIMISTIC_DELAY)}`) } + // Set item in the Cache Cache._items.set(key, { data: value, expires: expiresAt, optimistic: optimisticExpiry }); + + // Increase write metric Cache._metrics.writes++; } @@ -137,9 +143,9 @@ export class Cache { * ``` * * @param key - * @param optimistic Whether to serve expired items from the cache + * @param allowOptimism Whether to allow optimistically serve expired items from the cache */ - public static get(key: string, optimistic = false): T | null { + public static get(key: string, allowOptimism = false): T | null { // Return null if the item doesn't exist if (!Cache.exists(key)) { Cache._metrics.reads.miss++; @@ -147,14 +153,22 @@ export class Cache { } // Return null if the item expired - if (Cache.expired(key) && !optimistic) { + const itemHasExpired = Cache.expired(key); + const disallowOptimism = !allowOptimism; + if (itemHasExpired && disallowOptimism) { Cache._metrics.reads.miss++; return null; } - // Return the item's data + // Get item from cache + const item = Cache._items.get(key); + Contract.requireNotUndefined(item); + + // Increase hit counter Cache._metrics.reads.hit++; - return Cache._items.get(key)?.data; + + // Return Cache data + return item.data; } /** @@ -187,12 +201,17 @@ export class Cache { * @param key */ public static expired(key: string): boolean { - // If the item doesn't exist, return true - if (!Cache.exists(key)) return true; + // Get the item from cache + const item = Cache._items.get(key); - // Check if the expiry date is before our current date - if (!Cache._items.get(key)?.expires) return false; - return Cache._items.get(key)?.expires! < new Date(); + // Make sure the item exists + if(item === undefined) return true; + + // Make sure the item has an expiry + if(item.expires === null) return false; + + // Check whether the item has expired + return item.expires < new Date(); } /** @@ -207,11 +226,11 @@ export class Cache { * ``` * * @param key - * @param optimistic Whether to serve expired items from the cache + * @param allowOptimism Whether to allow optimistically serve expired items from the cache */ - public static consume(key: string, optimistic = false): T | null { + public static consume(key: string, allowOptimism = false): T | null { // Copy item from cache - const data = Cache.get(key, optimistic); + const data = Cache.get(key, allowOptimism); // Remove item from cache Cache.remove(key); @@ -257,7 +276,11 @@ export class Cache { */ public static async remember(key: string, expiry: string | null = "+1 minute", callable: Promise|(() => Promise)): Promise { // Check if cache item exists and hasn't expired - if(!Cache.expired(key)) return Cache.get(key); + // If so, return the cached item + const itemNotExpired = !Cache.expired(key); + if(itemNotExpired) return Cache.get(key); + + // Increase metrics Cache._metrics.reads.miss++; // Cache does not exist, run callable @@ -304,21 +327,22 @@ export class Cache { const now = new Date(); // Loop over each item in the cache - for (const [key, value] of Cache._items) { + for (const [key, item] of Cache._items) { // Keep items that do not expire - if (!value.expires) { + if (item.expires === null) { Logger.trace(`Keeping cache item "${key}": Does not expire`); continue; } // Keep items that have not yet expired - if (value.expires >= now) { + const itemNotExpired = item.expires >= now; + if (itemNotExpired) { Logger.trace(`Keeping cache item "${key}": Has not expired`); continue; } // Keep items that may be served optimistically - if (value.optimistic && value.optimistic >= now) { + if (item.optimistic !== undefined && item.optimistic >= now) { Logger.trace(`Keeping cache item "${key}": Keep for optimistic caching`); continue; } From 42ce7b48b980342f76787117659a336819f91315 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Nov 2025 00:36:40 +0100 Subject: [PATCH 340/379] Significantly rewrite Configure --- core/configure.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/configure.ts b/core/configure.ts index 28598dde..f05f70cb 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,6 +1,7 @@ import { Logger } from "./logger.ts"; import {valueOrDefault} from "../utility/value-or-default.ts"; import { File } from "../filesystem/file.ts"; +import {empty} from "../utility/empty.ts"; // deno-lint-ignore no-explicit-any -- Arbitrary data may be used const defaults = new Map([ @@ -72,7 +73,8 @@ export class Configure { const file = new File(`${Deno.cwd()}/config.json`); // Make sure our file exists - if(!await file.exists()) { + const isFileMissing = !await file.exists(); + if(isFileMissing) { Logger.warning(`Could not find file "config.json" at "${Deno.cwd()}". Configure will be empty!`); Configure.hasLoaded = true; return; @@ -139,7 +141,8 @@ export class Configure { */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static set(key: string, value: any): void { - if (value === null || typeof value === "undefined") return; + const hasData = empty(value); + if (!hasData) return; Configure.config.set(key, value); } @@ -185,7 +188,8 @@ export class Configure { */ public static consume(key: string, defaultValue: T|null = null): T { // Check if the key exists, if not, return the default value - if (!Configure.config.has(key)) return defaultValue as T; + const hasConfigureItem = Configure.config.has(key); + if (!hasConfigureItem) return defaultValue as T; // Hack together a reference to our item's value const ref = [Configure.config.get(key)]; From bdf3f62e8a96f537fadae3cbf732d0c3419ff8d6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Nov 2025 13:27:55 +0100 Subject: [PATCH 341/379] Allow Log levels to be enabled or disabled independently --- README.md | 3 ++- core/configure.ts | 4 ++-- core/logger.ts | 54 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index f18e6903..e5329721 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,9 @@ As a result, some things can be configured by you by adding entries to the Confi | Key | Default Value | Comment | |-----|---------------|-------------------------------------------------------------------------------------------------------------------------------------| -| `chomp_optimistic_delay` | `'+1 hour'` | Additional time a cache entry may exist for optimistic caching. Uses the `utility/time-string` formats | +| `chomp_optimistic_delay` | `'+1 hour'` | Additional time a cache entry may exist for optimistic caching. Uses the `utility/time-string` formats | | `chomp_couchdb_cache` | `'+1 hour'` | Time a document for `communication/couchdb` will be kept in the cache to improve read times. Uses the `utility/time-string` formats | + | `log_level` | `1.0` | Bitmask for the enabled log levels. | ### Extensions diff --git a/core/configure.ts b/core/configure.ts index f05f70cb..6d946c74 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,4 +1,4 @@ -import { Logger } from "./logger.ts"; +import {Logger, LogLevels} from "./logger.ts"; import {valueOrDefault} from "../utility/value-or-default.ts"; import { File } from "../filesystem/file.ts"; import {empty} from "../utility/empty.ts"; @@ -6,7 +6,7 @@ import {empty} from "../utility/empty.ts"; // deno-lint-ignore no-explicit-any -- Arbitrary data may be used const defaults = new Map([ ["debug", false], - ["log_level", 5], + ["log_level", LogLevels.All], ["error_log", `${Deno.cwd()}/logs/error.log`], ]); diff --git a/core/logger.ts b/core/logger.ts index 1d6addf2..bffa2369 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -2,6 +2,20 @@ import { Time } from "../utility/time.ts"; import { Configure } from "./configure.ts"; import { bold, cyan, magenta, red, yellow, blue, green, gray } from "https://deno.land/std@0.117.0/fmt/colors.ts"; +export enum LogLevels { + All = 1 << 0, + Error = 1 << 1, + Success = 1 << 2, + Warning = 1 << 3, + Notice = 1 << 4, + Info = 1 << 5, + Monitor= 1 << 6, + Debug = 1 << 7, + Trace = 1 << 8, +} + +type LogLevelKeys = keyof typeof LogLevels; + type Handlers = { error: (message: string, stack: string | null) => void; success: (message: string) => void; @@ -12,7 +26,8 @@ type Handlers = { debug: (message: string) => void; trace: (message: string) => void; }; -type LogLevels = keyof Handlers; + +type LogLevelHandlerKeys = keyof Handlers; const handlers: Handlers = { error: (message: string, stack: string | null = null): void => { @@ -76,13 +91,14 @@ export class Logger { * @param handler {any} */ // deno-lint-ignore no-explicit-any -- TODO: Figure out how to replace any type with something more sane - public static setHandler(level: LogLevels, handler: any): void { + public static setHandler(level: LogLevelHandlerKeys, handler: any): void { Logger._handlers[level] = handler; } /** * Write an error message to the console. - * If the "error_log" Configure item is set, will also write to file. + * + * Using the default handler, if the "error_log" Configure item is set, will also write to file. * * Available in any log level. * @@ -91,7 +107,7 @@ export class Logger { * @returns {void} */ public static error(message: string, stack: string | null = null): void { - Logger._handlers["error"](message, stack); + if(Logger.shouldLog("Error")) Logger._handlers["error"](message, stack); } /** @@ -103,7 +119,7 @@ export class Logger { * @returns {void} */ public static success(message: string): void { - Logger._handlers["success"](message); + if(Logger.shouldLog("Success")) Logger._handlers["success"](message); } /** @@ -115,7 +131,7 @@ export class Logger { * @returns {void} */ public static warning(message: string): void { - if(Logger.shouldLog(0)) Logger._handlers["warning"](message); + if(Logger.shouldLog("Warning")) Logger._handlers["warning"](message); } /** @@ -127,7 +143,7 @@ export class Logger { * @returns {void} */ public static notice(message: string): void { - if(Logger.shouldLog(1)) Logger._handlers["notice"](message); + if(Logger.shouldLog("Notice")) Logger._handlers["notice"](message); } /** @@ -139,7 +155,7 @@ export class Logger { * @returns {void} */ public static info(message: string): void { - if(Logger.shouldLog(2)) Logger._handlers["info"](message); + if(Logger.shouldLog("Info")) Logger._handlers["info"](message); } /** @@ -152,7 +168,7 @@ export class Logger { * @returns {void} */ public static monitor(message: string): void { - if(Logger.shouldLog(3)) Logger._handlers["monitor"](message); + if(Logger.shouldLog("Monitor")) Logger._handlers["monitor"](message); } /** @@ -164,7 +180,7 @@ export class Logger { * @returns {void} */ public static debug(message: string): void { - if(Logger.shouldLog(4)) Logger._handlers["debug"](message); + if(Logger.shouldLog("Debug")) Logger._handlers["debug"](message); } /** @@ -177,7 +193,7 @@ export class Logger { * @returns {void} */ public static trace(message: string): void { - if(Logger.shouldLog(5)) Logger._handlers["trace"](message); + if(Logger.shouldLog("Trace")) Logger._handlers["trace"](message); } /** @@ -198,7 +214,19 @@ export class Logger { * @param level * @private */ - private static shouldLog(level: number): boolean { - return Configure.get("log_level", 5) >= level; + private static shouldLog(level: LogLevelKeys): boolean { + // Get enabled log levels + const enabledLevels = Configure.get("log_level", LogLevels.All); + + // Check if log enabled levels includes "all" + const allEnabled = enabledLevels & LogLevels.All; + if(allEnabled) return true; + + // Get bitmask for requested level + const bitmask = LogLevels[level]; + + // Check whether the current level is enabled + const levelEnabled = enabledLevels & LogLevels[level]; + return levelEnabled; } } From 8a0ab1e789c6c24cdfaee68f7d25c01ddc7fa6ec Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Nov 2025 13:28:04 +0100 Subject: [PATCH 342/379] Fix some errors --- core/logger.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/logger.ts b/core/logger.ts index bffa2369..997b2941 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -209,7 +209,7 @@ export class Logger { } /** - * Check + * Check whether the log level is enabled * * @param level * @private @@ -219,14 +219,13 @@ export class Logger { const enabledLevels = Configure.get("log_level", LogLevels.All); // Check if log enabled levels includes "all" - const allEnabled = enabledLevels & LogLevels.All; + const allEnabled = (enabledLevels & LogLevels.All) === LogLevels.All; if(allEnabled) return true; // Get bitmask for requested level const bitmask = LogLevels[level]; // Check whether the current level is enabled - const levelEnabled = enabledLevels & LogLevels[level]; - return levelEnabled; + return (enabledLevels & bitmask) === bitmask; } } From 7c6f584bf0cadddf3c8ed89c55961109eb1e7753 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Nov 2025 13:43:53 +0100 Subject: [PATCH 343/379] Allow going either forward or backward --- extensions/date/set-midnight.ts | 23 ++++++++++++++++++++--- tests/extensions/date.test.ts | 2 ++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/extensions/date/set-midnight.ts b/extensions/date/set-midnight.ts index 97e8418e..1570f0db 100644 --- a/extensions/date/set-midnight.ts +++ b/extensions/date/set-midnight.ts @@ -3,14 +3,31 @@ */ declare global { interface Date { - setMidnight(): Date; + setMidnight: (goToTomorrow?: boolean) => Date; } } /** - * Set the date to midnight (00:00:00.000) + * Set the date to midnight (00:00:00.000). + * + * @example Basic usage + * ```ts + * const start = new Date('2025-09-16T12:13:56.123Z'); + * start.setMidnight(); + * console.log(start.toISOString()); // 2025-09-16T23:00:00.000Z + * ``` + * + * @example Go to tomorrow + * ```ts + * const start = new Date('2025-09-16T12:13:56.123Z'); + * start.setMidnight(true); + * console.log(start.toISOString()); // 2025-09-17T23:00:00.000Z + * ``` + * + * @param goToTomorrow Whether to set to midnight tomorrow */ -Date.prototype.setMidnight = function() { +Date.prototype.setMidnight = function(goToTomorrow: boolean = false) { this.setHours(0, 0, 0, 0); + if(goToTomorrow) this.setDate(this.getDate() + 1); return this; } diff --git a/tests/extensions/date.test.ts b/tests/extensions/date.test.ts index d2236fa5..09ef71bc 100644 --- a/tests/extensions/date.test.ts +++ b/tests/extensions/date.test.ts @@ -9,6 +9,7 @@ Deno.test("Date Extensions Test", async (t) => { const a = new Date(0); const b = new Date(1); const c = new Date('2025-09-16T12:13:56.123Z').setMidnight(); + const d = new Date('2025-09-16T12:13:56.123Z').setMidnight(true); await t.step("isAfter", () => { assertEquals(b.isAfter(a), true); @@ -36,6 +37,7 @@ Deno.test("Date Extensions Test", async (t) => { await t.step("setMidnight", () => { assertEquals(c.getTime(), 1757973600000); + assertEquals(d.getTime(), 1758060000000); assertEquals(a.isBeforeOrEqual(b), true); assertEquals(b.isBeforeOrEqual(a), false); assertEquals(b.isBeforeOrEqual(b), true); From 2a0c0e9ee936219c8b36671ae3f9abf6d6369523 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Nov 2025 13:49:08 +0100 Subject: [PATCH 344/379] Fix small error --- core/configure.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/configure.ts b/core/configure.ts index 6d946c74..029cb8d3 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -141,7 +141,7 @@ export class Configure { */ // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used public static set(key: string, value: any): void { - const hasData = empty(value); + const hasData = !empty(value); if (!hasData) return; Configure.config.set(key, value); } From 5f49108c770095e6583b2eb958440dd17bcb6a65 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Nov 2025 14:04:35 +0100 Subject: [PATCH 345/379] Start moving types to a different place --- core/cache.ts | 17 +---------------- core/configure.ts | 3 ++- core/logger.ts | 32 +++----------------------------- types/cache.ts | 16 ++++++++++++++++ types/logging.ts | 26 ++++++++++++++++++++++++++ 5 files changed, 48 insertions(+), 46 deletions(-) create mode 100644 types/cache.ts create mode 100644 types/logging.ts diff --git a/core/cache.ts b/core/cache.ts index 6be0a4e0..276a8e33 100644 --- a/core/cache.ts +++ b/core/cache.ts @@ -1,24 +1,9 @@ +import { CacheItem, CacheMetrics } from "../types/cache.ts"; import { TimeString } from "../utility/time-string.ts"; import { Logger } from "./logger.ts"; import { Configure } from "./configure.ts"; import {Contract} from "../utility/contract.ts"; -interface CacheItem { - // deno-lint-ignore no-explicit-any -- Any arbitrary data may be added to cache - data: any; - expires: Date | null; - optimistic?: Date; -} - -interface CacheMetrics { - reads: { - hit: number; - miss: number; - }; - writes: number; - swept: number; -} - /** * Default optimistic boundaries */ diff --git a/core/configure.ts b/core/configure.ts index 029cb8d3..8a635a80 100644 --- a/core/configure.ts +++ b/core/configure.ts @@ -1,4 +1,5 @@ -import {Logger, LogLevels} from "./logger.ts"; +import { LogLevels } from "../types/logging.ts"; +import {Logger} from "./logger.ts"; import {valueOrDefault} from "../utility/value-or-default.ts"; import { File } from "../filesystem/file.ts"; import {empty} from "../utility/empty.ts"; diff --git a/core/logger.ts b/core/logger.ts index 997b2941..a63db18c 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -1,35 +1,9 @@ +import { LogLevels, LogLevelKeys, LogHandlers, LogLevelHandlerKeys } from "../types/logging.ts"; import { Time } from "../utility/time.ts"; import { Configure } from "./configure.ts"; import { bold, cyan, magenta, red, yellow, blue, green, gray } from "https://deno.land/std@0.117.0/fmt/colors.ts"; -export enum LogLevels { - All = 1 << 0, - Error = 1 << 1, - Success = 1 << 2, - Warning = 1 << 3, - Notice = 1 << 4, - Info = 1 << 5, - Monitor= 1 << 6, - Debug = 1 << 7, - Trace = 1 << 8, -} - -type LogLevelKeys = keyof typeof LogLevels; - -type Handlers = { - error: (message: string, stack: string | null) => void; - success: (message: string) => void; - warning: (message: string) => void; - notice: (message: string) => void; - info: (message: string) => void; - monitor: (message: string) => void; - debug: (message: string) => void; - trace: (message: string) => void; -}; - -type LogLevelHandlerKeys = keyof Handlers; - -const handlers: Handlers = { +const handlers: LogHandlers = { error: (message: string, stack: string | null = null): void => { // Get current time const now = Logger.time(); @@ -82,7 +56,7 @@ const handlers: Handlers = { * Logging handler for writing to console */ export class Logger { - private static _handlers: Handlers = handlers; + private static _handlers: LogHandlers = handlers; /** * Override a handler app-wide. diff --git a/types/cache.ts b/types/cache.ts new file mode 100644 index 00000000..c9d8b127 --- /dev/null +++ b/types/cache.ts @@ -0,0 +1,16 @@ +export type CacheItem = { + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be added to cache + data: any; + expires: Date | null; + optimistic?: Date; +} + +export type CacheMetrics = { + reads: { + hit: number; + miss: number; + }; + writes: number; + swept: number; +} + diff --git a/types/logging.ts b/types/logging.ts new file mode 100644 index 00000000..a76a9484 --- /dev/null +++ b/types/logging.ts @@ -0,0 +1,26 @@ +export enum LogLevels { + All = 1 << 0, + Error = 1 << 1, + Success = 1 << 2, + Warning = 1 << 3, + Notice = 1 << 4, + Info = 1 << 5, + Monitor= 1 << 6, + Debug = 1 << 7, + Trace = 1 << 8, +} + +export type LogHandlers = { + error: (message: string, stack: string | null) => void; + success: (message: string) => void; + warning: (message: string) => void; + notice: (message: string) => void; + info: (message: string) => void; + monitor: (message: string) => void; + debug: (message: string) => void; + trace: (message: string) => void; +}; + + +export type LogLevelKeys = keyof typeof LogLevels; +export type LogLevelHandlerKeys = keyof LogHandlers; From 1d77d89a31a3057d8d2aad400320a6d3464d7302 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Nov 2025 16:57:34 +0100 Subject: [PATCH 346/379] Export all by default --- core/mod.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/mod.ts b/core/mod.ts index cbc93b47..0053c51e 100644 --- a/core/mod.ts +++ b/core/mod.ts @@ -1,3 +1,3 @@ -export { Cache } from "./cache.ts"; -export { Configure } from "./configure.ts"; -export { Logger } from "./logger.ts"; +export * from "./cache.ts"; +export * from "./configure.ts"; +export * from "./logger.ts"; From 5c38a631938e322e2fed9d627e3432325c31e9e9 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 27 Nov 2025 16:57:53 +0100 Subject: [PATCH 347/379] Export log levels --- core/logger.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/logger.ts b/core/logger.ts index a63db18c..5223b29f 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -3,6 +3,8 @@ import { Time } from "../utility/time.ts"; import { Configure } from "./configure.ts"; import { bold, cyan, magenta, red, yellow, blue, green, gray } from "https://deno.land/std@0.117.0/fmt/colors.ts"; +export { LogLevels }; + const handlers: LogHandlers = { error: (message: string, stack: string | null = null): void => { // Get current time From 620825daefeee8fb80b3bfdfebf90e31e5876114 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 13:05:44 +0100 Subject: [PATCH 348/379] Move types around --- communication/couchdb.ts | 55 +----- communication/influxdb.ts | 14 +- communication/loki.ts | 7 +- communication/nut.ts | 6 +- communication/rcon.ts | 6 +- communication/uptime-kuma.ts | 6 +- core/logger.ts | 3 + deno.lock | 4 + interfaces/window.interface.ts | 7 - queue/queue.ts | 17 +- queue/scheduler/first-in-first-out.ts | 2 +- queue/scheduler/last-in-first-out.ts | 2 +- .../scheduler/weighted-first-in-first-out.ts | 2 +- security/hash.ts | 49 +----- security/password.ts | 53 +----- types/check-source.ts | 4 + types/couchdb.ts | 51 ++++++ types/error-or-data.ts | 1 + types/hash.ts | 45 +++++ types/influxdb.ts | 12 ++ types/loki.ts | 5 + types/nut.ts | 4 + types/password.ts | 47 ++++++ types/queue.ts | 15 ++ types/rcon.ts | 4 + types/uptime-kuma.ts | 4 + types/validator.ts | 22 +++ types/webserver.ts | 158 ++++++++++++++++++ types/websocket.ts | 4 + utility/check-source.ts | 6 +- utility/error-or-data.ts | 2 +- utility/time-string.ts | 8 - validation/rules.ts | 2 +- validation/rules/is-empty.ts | 2 +- validation/rules/is-null.ts | 2 +- validation/rules/is-undefined.ts | 2 +- validation/rules/max-length.ts | 2 +- validation/rules/min-length.ts | 2 +- validation/validator.ts | 18 +- webserver/controller/controller.ts | 5 +- webserver/http/request.ts | 9 +- webserver/http/response-builder.ts | 5 +- webserver/pathToRegexp.ts | 136 ++------------- webserver/registry/registry.ts | 4 +- webserver/renderers/handlebars.ts | 9 +- webserver/routing/router.ts | 10 +- websocket/events.ts | 6 +- websocket/websocket.ts | 6 + 48 files changed, 437 insertions(+), 408 deletions(-) delete mode 100644 interfaces/window.interface.ts create mode 100644 types/check-source.ts create mode 100644 types/couchdb.ts create mode 100644 types/error-or-data.ts create mode 100644 types/hash.ts create mode 100644 types/influxdb.ts create mode 100644 types/loki.ts create mode 100644 types/nut.ts create mode 100644 types/password.ts create mode 100644 types/queue.ts create mode 100644 types/rcon.ts create mode 100644 types/uptime-kuma.ts create mode 100644 types/validator.ts create mode 100644 types/webserver.ts create mode 100644 types/websocket.ts diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 2d7bcbe3..0149ad22 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -1,57 +1,6 @@ +import { Auth, CouchResponse, CouchRequest, CachedResponse, CouchOverrides} from "../types/couchdb.ts"; import { Cache } from "../core/cache.ts"; -import {Configure} from "../core/configure.ts"; - -type Auth = { - username: string; - password: string; -} - -type CouchRequest = { - method: string; - // deno-lint-ignore no-explicit-any -- TODO: Figure out proper type - headers: any; - body?: string; -} - -type CachedResponse = { - etag: string; - data: CouchResponse; -} - -export type CouchFailure = [ - // Error data - { error: string; reason: string; } | undefined, - - // No document - undefined, - - // HTTP Status code - number, -] - -export type CouchSuccess = [ - // No error - undefined, - - // Document - // deno-lint-ignore no-explicit-any -- TODO: Figure out proper type - DocumentHeader & any, - - // HTTP Status code - number, -] - -export type CouchResponse = CouchSuccess|CouchFailure; - -export interface CouchOverrides { - method?: string; - etag?: string; -} - -export type DocumentHeader = { - _id: string; - _rev?: string; -} +import { Configure } from "../core/configure.ts"; const CACHE_TIME = '+1 hour'; diff --git a/communication/influxdb.ts b/communication/influxdb.ts index 3e7de389..a2284994 100644 --- a/communication/influxdb.ts +++ b/communication/influxdb.ts @@ -1,18 +1,6 @@ +import { Precision, Api } from "../types/influxdb.ts"; import { Logger } from "../core/logger.ts"; -export enum Precision { - s, - ms, - us, - ns, -} - -interface Api { - url: string; - auth: string; - precision: Precision; -} - /** * Interact with InfluxDB */ diff --git a/communication/loki.ts b/communication/loki.ts index 13214d77..6d948070 100644 --- a/communication/loki.ts +++ b/communication/loki.ts @@ -1,11 +1,6 @@ +import { LokiStream } from "../types/loki.ts"; import { Logger } from "../core/logger.ts"; -export interface LokiStream { - // deno-lint-ignore no-explicit-any -- TODO - stream: any; - values: Array>; -} - /** * Interact with {@link https://grafana.com/oss/loki/ Loki}. */ diff --git a/communication/nut.ts b/communication/nut.ts index f5cee6c3..67ae3db8 100644 --- a/communication/nut.ts +++ b/communication/nut.ts @@ -1,10 +1,6 @@ +import { NutState } from "../types/nut.ts"; import { Logger } from "../core/logger.ts"; -export class NutState { - public static readonly WAITING = 0; - public static readonly IDLE = 1; -} - /** * Interact with NUT (Network UPS Tools). */ diff --git a/communication/rcon.ts b/communication/rcon.ts index 13d27b07..1c1f0219 100644 --- a/communication/rcon.ts +++ b/communication/rcon.ts @@ -1,10 +1,6 @@ +import { PacketType } from "../types/rcon.ts"; import { Buffer } from "https://deno.land/std@0.87.0/node/buffer.ts"; -export enum PacketType { - COMMAND = 0x02, - AUTH = 0x03, -} - /** * Interact with RCON. */ diff --git a/communication/uptime-kuma.ts b/communication/uptime-kuma.ts index d472ac85..08854275 100644 --- a/communication/uptime-kuma.ts +++ b/communication/uptime-kuma.ts @@ -1,11 +1,7 @@ +import { UptimeKumaInstance } from "../types/uptime-kuma.ts"; import {fetchWithTimeout} from "../utility/fetch-with-timeout.ts"; import {raise} from "../mod.ts"; -export interface UptimeKumaInstance { - host?: string; - id: string; -} - export class UptimeKuma { private readonly _host: string = 'http://localhost:3001'; private readonly _id: string; diff --git a/core/logger.ts b/core/logger.ts index 5223b29f..3c543c6f 100644 --- a/core/logger.ts +++ b/core/logger.ts @@ -3,6 +3,9 @@ import { Time } from "../utility/time.ts"; import { Configure } from "./configure.ts"; import { bold, cyan, magenta, red, yellow, blue, green, gray } from "https://deno.land/std@0.117.0/fmt/colors.ts"; +/** + * Exporting LogLevels to make it easier to use this class. + */ export { LogLevels }; const handlers: LogHandlers = { diff --git a/deno.lock b/deno.lock index a187316c..9a40fec9 100644 --- a/deno.lock +++ b/deno.lock @@ -9,6 +9,10 @@ "https://deno.land/std@0.152.0/testing/_diff.ts": "029a00560b0d534bc0046f1bce4bd36b3b41ada3f2a3178c85686eb2ff5f1413", "https://deno.land/std@0.152.0/testing/_format.ts": "0d8dc79eab15b67cdc532826213bbe05bccfd276ca473a50a3fc7bbfb7260642", "https://deno.land/std@0.152.0/testing/asserts.ts": "093735c88f52bbead7f60a1f7a97a2ce4df3c2d5fab00a46956f20b4a5793ccd", + "https://deno.land/std@0.159.0/fmt/colors.ts": "ff7dc9c9f33a72bd48bc24b21bbc1b4545d8494a431f17894dbc5fe92a938fc4", + "https://deno.land/std@0.159.0/testing/_diff.ts": "a23e7fc2b4d8daa3e158fa06856bedf5334ce2a2831e8bf9e509717f455adb2c", + "https://deno.land/std@0.159.0/testing/_format.ts": "cd11136e1797791045e639e9f0f4640d5b4166148796cad37e6ef75f7d7f3832", + "https://deno.land/std@0.159.0/testing/asserts.ts": "9ff3259f6cdc2908af478f9340f4e470d23234324bd33e7f74c683a00ed4d211", "https://deno.land/x/croner@5.3.4/src/croner.js": "a7e06cd5c262c60bc9736d735eb65ae2e401eed3d965c467087a5a575abd8ec2", "https://deno.land/x/croner@5.3.4/src/date.js": "e5bfdf17750207a00e1399c50bda7be8746429619c9f2fc0679c678aed22febc", "https://deno.land/x/croner@5.3.4/src/helpers/minitz.js": "8b3824fadd0130b4faf38335a064febdf77c5582dcaa06f443b901e9b8233130", diff --git a/interfaces/window.interface.ts b/interfaces/window.interface.ts deleted file mode 100644 index 9cf1293c..00000000 --- a/interfaces/window.interface.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Websocket } from "../websocket/websocket.ts"; - -declare global { - interface Window { - websocket: Websocket; - } -} diff --git a/queue/queue.ts b/queue/queue.ts index 9b8f6b93..b23c820a 100644 --- a/queue/queue.ts +++ b/queue/queue.ts @@ -1,21 +1,6 @@ +import { QueueItem, Scheduler } from "../types/queue.ts"; import { default as defaultScheduler } from "./scheduler/first-in-first-out.ts"; -export type QueueItem = { - /** - * Weight for the item. - * Only used in weighted algorithms. - */ - weight?: number; - - /** - * Main data for the QueueItem - */ - // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used - data: any; -} - -export type Scheduler = (item: QueueItem, items: QueueItem[]) => QueueItem[]; - /** * Crude yet effective in-memory Queue system */ diff --git a/queue/scheduler/first-in-first-out.ts b/queue/scheduler/first-in-first-out.ts index 1fcafb83..69c249b4 100644 --- a/queue/scheduler/first-in-first-out.ts +++ b/queue/scheduler/first-in-first-out.ts @@ -1,4 +1,4 @@ -import {QueueItem} from "../queue.ts"; +import {QueueItem} from "../../types/queue.ts"; export default function(item: QueueItem, items: QueueItem[] = []) { // Remove weight if specified diff --git a/queue/scheduler/last-in-first-out.ts b/queue/scheduler/last-in-first-out.ts index be7bff5b..d82d7d29 100644 --- a/queue/scheduler/last-in-first-out.ts +++ b/queue/scheduler/last-in-first-out.ts @@ -1,4 +1,4 @@ -import {QueueItem} from "../queue.ts"; +import {QueueItem} from "../../types/queue.ts"; export default function(item: QueueItem, items: QueueItem[] = []) { // Remove weight if specified diff --git a/queue/scheduler/weighted-first-in-first-out.ts b/queue/scheduler/weighted-first-in-first-out.ts index b055587b..b33a11e4 100644 --- a/queue/scheduler/weighted-first-in-first-out.ts +++ b/queue/scheduler/weighted-first-in-first-out.ts @@ -1,4 +1,4 @@ -import {QueueItem} from "../queue.ts"; +import {QueueItem} from "../../types/queue.ts"; import {valueOrDefault} from "../../utility/value-or-default.ts"; export default function(item: QueueItem, items: QueueItem[] = []) { diff --git a/security/hash.ts b/security/hash.ts index f147b34c..d2a5d5cb 100644 --- a/security/hash.ts +++ b/security/hash.ts @@ -1,52 +1,7 @@ +import { Algorithms } from "../types/hash.ts"; import { DigestAlgorithm } from "https://cdn.deno.land/std/versions/0.113.0/raw/_wasm_crypto/mod.ts"; import { crypto } from "https://deno.land/std@0.113.0/crypto/mod.ts"; -/** - * List of algorithms supported by this library - */ -export enum Algorithms { - SHA384 = "SHA-384", - SHA3_224 = "SHA3-224", - SHA3_256 = "SHA3-256", - SHA3_384 = "SHA3-384", - SHA3_512 = "SHA3-512", - SHAKE128 = "SHAKE128", - SHAKE256 = "SHAKE256", - BLAKE2B256 = "BLAKE2B-256", - BLAKE2B384 = "BLAKE2B-384", - BLAKE2B = "BLAKE2B", - BLAKE2S = "BLAKE2S", - BLAKE3 = "BLAKE3", - KECCAK224 = "KECCAK-224", - KECCAK256 = "KECCAK-256", - KECCAK384 = "KECCAK-384", - KECCAK512 = "KECCAK-512", - /* Insecure, please do not use in production */ - RIPEMD160 = "RIPEMD-160", - /* Insecure, please do not use in production */ - SHA224 = "SHA-224", - /* Insecure, please do not use in production */ - SHA256 = "SHA-256", - /* Insecure, please do not use in production */ - SHA512 = "SHA-512", - /* Insecure, please do not use in production */ - SHA1 = "SHA-1", - /* Insecure, please do not use in production */ - MD5 = "MD5", -} - -/** - * Specify algorithms that are supported but deemed insecure - */ -export const INSECURE_ALGORITHMS: string[] = [ - Algorithms.RIPEMD160, - Algorithms.SHA224, - Algorithms.SHA256, - Algorithms.SHA512, - Algorithms.SHA1, - Algorithms.MD5, -]; - /** * Create hashes * @@ -57,7 +12,7 @@ export class Hash { constructor( private input: string, - private algo: string, + private algo: Algorithms, ) {} /** diff --git a/security/password.ts b/security/password.ts index 8284fa8f..17f37223 100644 --- a/security/password.ts +++ b/security/password.ts @@ -1,5 +1,8 @@ +import { Algorithms, INSECURE_ALGORITHMS } from "../types/hash.ts"; +import { PasswordOptions, HASH_IDENTIFIERS } from "../types/password.ts"; +import { Hash } from "./hash.ts"; import { Random } from "./random.ts"; -import { Algorithms, Hash, INSECURE_ALGORITHMS } from "./hash.ts"; + /** * Recommended hashing algorithm for most use-cases. @@ -7,43 +10,7 @@ import { Algorithms, Hash, INSECURE_ALGORITHMS } from "./hash.ts"; */ export const PASSWORD_DEFAULT = Algorithms.SHA3_256; -/** - * Create a mapping of algorithms to identifiers - * To add new identifier: - * - Hash enum value using SHA1 - * - Add first 2 characters as identifier - * - Prefix with "d" (to make linter happy) - */ -enum HASH_IDENTIFIERS { - "d5e" = "SHA-384", - "d6d" = "SHA3-224", - "d88" = "SHA3-256", - "def" = "SHA3-384", - "d81" = "SHA3-512", - "dfa" = "SHAKE128", - "de3" = "SHAKE256", - "d34" = "BLAKE2B-256", - "d20" = "BLAKE2B-384", - "d85" = "BLAKE2B", - "d05" = "BLAKE2S", - "d63" = "BLAKE3", - "d87" = "KECCAK-224", - "d78" = "KECCAK-256", - "d1c" = "KECCAK-384", - "df6" = "KECCAK-512", - /* Insecure, please do not use in production */ - "dc0" = "RIPEMD-160", - /* Insecure, please do not use in production */ - "dba" = "SHA-224", - /* Insecure, please do not use in production */ - "d45" = "SHA-256", - /* Insecure, please do not use in production */ - "db8" = "SHA-512", - /* Insecure, please do not use in production */ - "dc5" = "SHA-1", - /* Insecure, please do not use in production */ - "db7" = "MD5", -} + /** * Default options for password hashing. @@ -54,16 +21,6 @@ export const DEFAULT_OPTS: PasswordOptions = { allowInsecure: false, }; -/** - * Options for hashing a password - */ -export interface PasswordOptions { - /* Cost factor for hashing (2**cost) */ - cost?: number; - /* Allow the use of insecure algorithms */ - allowInsecure?: boolean; -} - /** * Create password hashes and easily verify them. * Automatically salts the hashes. diff --git a/types/check-source.ts b/types/check-source.ts new file mode 100644 index 00000000..eebdb2f2 --- /dev/null +++ b/types/check-source.ts @@ -0,0 +1,4 @@ +export interface ExclusionConfig { + directories?: string[]; + files?: string[]; +} diff --git a/types/couchdb.ts b/types/couchdb.ts new file mode 100644 index 00000000..ba4a4a48 --- /dev/null +++ b/types/couchdb.ts @@ -0,0 +1,51 @@ +export type Auth = { + username: string; + password: string; +} + +export type CouchRequest = { + method: string; + // deno-lint-ignore no-explicit-any -- TODO: Figure out proper type + headers: any; + body?: string; +} + +export type CachedResponse = { + etag: string; + data: CouchResponse; +} + +export type CouchFailure = [ + // Error data + { error: string; reason: string; } | undefined, + + // No document + undefined, + + // HTTP Status code + number, +] + +export type CouchSuccess = [ + // No error + undefined, + + // Document + // deno-lint-ignore no-explicit-any -- TODO: Figure out proper type + DocumentHeader & any, + + // HTTP Status code + number, +] + +export type CouchResponse = CouchSuccess|CouchFailure; + +export interface CouchOverrides { + method?: string; + etag?: string; +} + +export type DocumentHeader = { + _id: string; + _rev?: string; +} diff --git a/types/error-or-data.ts b/types/error-or-data.ts new file mode 100644 index 00000000..62f0c36a --- /dev/null +++ b/types/error-or-data.ts @@ -0,0 +1 @@ +export type SuccessResponse = [undefined, T]; diff --git a/types/hash.ts b/types/hash.ts new file mode 100644 index 00000000..e45b4a5c --- /dev/null +++ b/types/hash.ts @@ -0,0 +1,45 @@ +/** + * List of algorithms supported by this library + */ +export enum Algorithms { + SHA384 = "SHA-384", + SHA3_224 = "SHA3-224", + SHA3_256 = "SHA3-256", + SHA3_384 = "SHA3-384", + SHA3_512 = "SHA3-512", + SHAKE128 = "SHAKE128", + SHAKE256 = "SHAKE256", + BLAKE2B256 = "BLAKE2B-256", + BLAKE2B384 = "BLAKE2B-384", + BLAKE2B = "BLAKE2B", + BLAKE2S = "BLAKE2S", + BLAKE3 = "BLAKE3", + KECCAK224 = "KECCAK-224", + KECCAK256 = "KECCAK-256", + KECCAK384 = "KECCAK-384", + KECCAK512 = "KECCAK-512", + /* Insecure, please do not use in production */ + RIPEMD160 = "RIPEMD-160", + /* Insecure, please do not use in production */ + SHA224 = "SHA-224", + /* Insecure, please do not use in production */ + SHA256 = "SHA-256", + /* Insecure, please do not use in production */ + SHA512 = "SHA-512", + /* Insecure, please do not use in production */ + SHA1 = "SHA-1", + /* Insecure, please do not use in production */ + MD5 = "MD5", +} + +/** + * Specify algorithms that are supported but deemed insecure + */ +export const INSECURE_ALGORITHMS: string[] = [ + Algorithms.RIPEMD160, + Algorithms.SHA224, + Algorithms.SHA256, + Algorithms.SHA512, + Algorithms.SHA1, + Algorithms.MD5, +]; diff --git a/types/influxdb.ts b/types/influxdb.ts new file mode 100644 index 00000000..bfffb00e --- /dev/null +++ b/types/influxdb.ts @@ -0,0 +1,12 @@ +export enum Precision { + s, + ms, + us, + ns, +} + +export interface Api { + url: string; + auth: string; + precision: Precision; +} diff --git a/types/loki.ts b/types/loki.ts new file mode 100644 index 00000000..a6163ca2 --- /dev/null +++ b/types/loki.ts @@ -0,0 +1,5 @@ +export interface LokiStream { + // deno-lint-ignore no-explicit-any -- TODO + stream: any; + values: Array>; +} diff --git a/types/nut.ts b/types/nut.ts new file mode 100644 index 00000000..448215ca --- /dev/null +++ b/types/nut.ts @@ -0,0 +1,4 @@ +export class NutState { + public static readonly WAITING = 0; + public static readonly IDLE = 1; +} diff --git a/types/password.ts b/types/password.ts new file mode 100644 index 00000000..e1f7c938 --- /dev/null +++ b/types/password.ts @@ -0,0 +1,47 @@ +/** + * Create a mapping of algorithms to identifiers + * To add new identifier: + * - Hash enum value using SHA1 + * - Add first 2 characters as identifier + * - Prefix with "d" (to make linter happy) + */ +export enum HASH_IDENTIFIERS { + "d5e" = "SHA-384", + "d6d" = "SHA3-224", + "d88" = "SHA3-256", + "def" = "SHA3-384", + "d81" = "SHA3-512", + "dfa" = "SHAKE128", + "de3" = "SHAKE256", + "d34" = "BLAKE2B-256", + "d20" = "BLAKE2B-384", + "d85" = "BLAKE2B", + "d05" = "BLAKE2S", + "d63" = "BLAKE3", + "d87" = "KECCAK-224", + "d78" = "KECCAK-256", + "d1c" = "KECCAK-384", + "df6" = "KECCAK-512", + /* Insecure, please do not use in production */ + "dc0" = "RIPEMD-160", + /* Insecure, please do not use in production */ + "dba" = "SHA-224", + /* Insecure, please do not use in production */ + "d45" = "SHA-256", + /* Insecure, please do not use in production */ + "db8" = "SHA-512", + /* Insecure, please do not use in production */ + "dc5" = "SHA-1", + /* Insecure, please do not use in production */ + "db7" = "MD5", +} + +/** + * Options for hashing a password + */ +export interface PasswordOptions { + /* Cost factor for hashing (2**cost) */ + cost?: number; + /* Allow the use of insecure algorithms */ + allowInsecure?: boolean; +} diff --git a/types/queue.ts b/types/queue.ts new file mode 100644 index 00000000..904c70be --- /dev/null +++ b/types/queue.ts @@ -0,0 +1,15 @@ +export type QueueItem = { + /** + * Weight for the item. + * Only used in weighted algorithms. + */ + weight?: number; + + /** + * Main data for the QueueItem + */ + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used + data: any; +} + +export type Scheduler = (item: QueueItem, items: QueueItem[]) => QueueItem[]; diff --git a/types/rcon.ts b/types/rcon.ts new file mode 100644 index 00000000..c317a5d1 --- /dev/null +++ b/types/rcon.ts @@ -0,0 +1,4 @@ +export enum PacketType { + COMMAND = 0x02, + AUTH = 0x03, +} diff --git a/types/uptime-kuma.ts b/types/uptime-kuma.ts new file mode 100644 index 00000000..8201d1dd --- /dev/null +++ b/types/uptime-kuma.ts @@ -0,0 +1,4 @@ +export interface UptimeKumaInstance { + host?: string; + id: string; +} diff --git a/types/validator.ts b/types/validator.ts new file mode 100644 index 00000000..84bd4461 --- /dev/null +++ b/types/validator.ts @@ -0,0 +1,22 @@ +export type ValidationCallback = (input: any, parameters: any) => ValidationCallbackResponse; + +export type ValidationCallbackResponse = ValidationCallbackSuccess|ValidationCallbackError; + +export type ValidationCallbackParameters = ValidationParameter[]; + +export type ValidationOptions = { + last?: boolean; + message?: string; + parameters?: ValidationCallbackParameters; +}; + +export type ValidationStep = { + callback: ValidationCallback + options: ValidationOptions; +}; + +export type ValidationCallbackSuccess = [undefined]; + +export type ValidationCallbackError = [string]; + +export type ValidationParameter = {[key: string]: any}; diff --git a/types/webserver.ts b/types/webserver.ts new file mode 100644 index 00000000..90e3e268 --- /dev/null +++ b/types/webserver.ts @@ -0,0 +1,158 @@ +export interface ViewVariable { + [key: string]: string | number | unknown; +} + +export interface RequestParameters { + [name: string]: string; +} + +export interface QueryParameters { + [name: string]: string; +} + +export interface ResponseHeader { + [key: string]: string; +} + +export interface RegistryItem { + [key: string]: any; +} + +export interface HandlebarsCacheItem { + // deno-lint-ignore ban-types -- TODO + [key: string]: Function; +} + +export interface Route { + path: string; + controller: string; + action: string; + method?: string; +} + +/** + * Tokenizer results. + */ +export interface LexToken { + type: + | "OPEN" + | "CLOSE" + | "PATTERN" + | "NAME" + | "CHAR" + | "ESCAPED_CHAR" + | "MODIFIER" + | "END"; + index: number; + value: string; +} + +export interface RegexpToFunctionOptions { + /** + * Function for decoding strings for params. + */ + decode?: (value: string, token: Key) => string; +} + +/** + * A match result contains data about the path match. + */ +export interface MatchResult

{ + path: string; + index: number; + params: P; +} + +/** + * A match is either `false` (no match) or a match result. + */ +export type Match

= false | MatchResult

; + +/** + * The match function takes a string and returns whether it matched the path. + */ +export type MatchFunction

= ( + path: string, +) => Match

; + + +/** + * Metadata about a key. + */ +export interface Key { + name: string | number; + prefix: string; + suffix: string; + pattern: string; + modifier: string; +} + +/** + * A token is a string (nothing special) or key metadata (capture group). + */ +export type Token = string | Key; + +export interface TokensToRegexpOptions { + /** + * When `true` the regexp will be case sensitive. (default: `false`) + */ + sensitive?: boolean; + /** + * When `true` the regexp won't allow an optional trailing delimiter to match. (default: `false`) + */ + strict?: boolean; + /** + * When `true` the regexp will match to the end of the string. (default: `true`) + */ + end?: boolean; + /** + * When `true` the regexp will match from the beginning of the string. (default: `true`) + */ + start?: boolean; + /** + * Sets the final character for non-ending optimistic matches. (default: `/`) + */ + delimiter?: string; + /** + * List of characters that can also be "end" characters. + */ + endsWith?: string; + /** + * Encode path tokens for use in the `RegExp`. + */ + encode?: (value: string) => string; +} + +/** + * Supported `path-to-regexp` input types. + */ +export type Path = string | RegExp | Array; + +export type PathFunction

= (data?: P) => string; + + +export interface TokensToFunctionOptions { + /** + * When `true` the regexp will be case sensitive. (default: `false`) + */ + sensitive?: boolean; + /** + * Function for encoding input strings for output. + */ + encode?: (value: string, token: Key) => string; + /** + * When `false` the function can produce an invalid (unmatched) path. (default: `true`) + */ + validate?: boolean; +} + +export interface ParseOptions { + /** + * Set the default delimiter for repeat parameters. (default: `'/'`) + */ + delimiter?: string; + /** + * List of characters to automatically consider prefixes when parsing. + */ + prefixes?: string; +} diff --git a/types/websocket.ts b/types/websocket.ts new file mode 100644 index 00000000..fd322aaa --- /dev/null +++ b/types/websocket.ts @@ -0,0 +1,4 @@ +export interface IEvent { + name: string; + handler: string; +} diff --git a/utility/check-source.ts b/utility/check-source.ts index 704e8670..c6ada445 100644 --- a/utility/check-source.ts +++ b/utility/check-source.ts @@ -1,11 +1,7 @@ +import { ExclusionConfig } from "../types/check-source.ts"; import { Logger } from "../core/logger.ts"; import { File } from "../filesystem/file.ts"; -export interface ExclusionConfig { - directories?: string[]; - files?: string[]; -} - /** * Check all files in the specified directories. * Doing this allows the program to start up significantly faster after deployment. diff --git a/utility/error-or-data.ts b/utility/error-or-data.ts index 78fa7dcb..84bae9a1 100644 --- a/utility/error-or-data.ts +++ b/utility/error-or-data.ts @@ -1,4 +1,4 @@ -type SuccessResponse = [undefined, T]; +import { SuccessResponse } from "../types/error-or-data.ts"; export async function errorOrData Error>(promise: Promise, catchables?: E[]): Promise | [InstanceType]> { try { diff --git a/utility/time-string.ts b/utility/time-string.ts index 40b38ba0..8ccd4460 100644 --- a/utility/time-string.ts +++ b/utility/time-string.ts @@ -2,14 +2,6 @@ * Thanks to Mordo95 for this code * https://github.com/Mordo95/interval-template-strings/blob/35d55c86ee8cbff947b66740b327e1de4d4f96aa/index.js */ - -interface RegExp { - groups: { - digit: number; - format: string; - }; -} - const TimeRegexp = /(?[+-]?\d+(\.\d+)?)\s*(?[a-zA-Z]+)/g; const second = 1000; const minute = second * 60; diff --git a/validation/rules.ts b/validation/rules.ts index 7e78922e..09470086 100644 --- a/validation/rules.ts +++ b/validation/rules.ts @@ -1,4 +1,4 @@ -import { ValidationCallback } from "./validator.ts"; +import { ValidationCallback } from "../types/validator.ts"; import { isEmpty } from "./rules/is-empty.ts"; import { isNull } from "./rules/is-null.ts"; import { isUndefined } from "./rules/is-undefined.ts"; diff --git a/validation/rules/is-empty.ts b/validation/rules/is-empty.ts index e3561c76..c11db617 100644 --- a/validation/rules/is-empty.ts +++ b/validation/rules/is-empty.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; export function isEmpty(input: any, options: ValidationOptions): ValidationCallbackResponse { // Check if empty string diff --git a/validation/rules/is-null.ts b/validation/rules/is-null.ts index d2e44d65..e2d73dcc 100644 --- a/validation/rules/is-null.ts +++ b/validation/rules/is-null.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; export function isNull(input: any, options: ValidationOptions): ValidationCallbackResponse { if(input === null) return [undefined]; diff --git a/validation/rules/is-undefined.ts b/validation/rules/is-undefined.ts index ab70e80d..99911fd6 100644 --- a/validation/rules/is-undefined.ts +++ b/validation/rules/is-undefined.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; export function isUndefined(input: any, options: ValidationOptions): ValidationCallbackResponse { if(input === undefined) return [undefined]; diff --git a/validation/rules/max-length.ts b/validation/rules/max-length.ts index fbdcc0b7..f9561d87 100644 --- a/validation/rules/max-length.ts +++ b/validation/rules/max-length.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; import {valueOrDefault} from "../../utility/value-or-default.ts"; export function maxLength(input: any, options: ValidationOptions): ValidationCallbackResponse { diff --git a/validation/rules/min-length.ts b/validation/rules/min-length.ts index bf20b2fc..0fd57f24 100644 --- a/validation/rules/min-length.ts +++ b/validation/rules/min-length.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; import {valueOrDefault} from "../../utility/value-or-default.ts"; export function minLength(input: any, options: ValidationOptions): ValidationCallbackResponse { diff --git a/validation/validator.ts b/validation/validator.ts index 151ad72e..405cf842 100644 --- a/validation/validator.ts +++ b/validation/validator.ts @@ -1,23 +1,7 @@ +import { ValidationCallback, ValidationOptions, ValidationStep } from "../types/validator.ts"; import {raise} from "../error/raise.ts"; import { Validators } from "./rules.ts"; -export type ValidationCallback = (input: any, parameters: any) => ValidationCallbackResponse; -export type ValidationCallbackResponse = ValidationCallbackSuccess|ValidationCallbackError; -export type ValidationCallbackParameters = ValidationParameter[]; -export type ValidationOptions = { - last?: boolean; - message?: string; - parameters?: ValidationCallbackParameters; -}; - -type ValidationStep = { - callback: ValidationCallback - options: ValidationOptions; -}; -type ValidationCallbackSuccess = [undefined]; -type ValidationCallbackError = [string]; -type ValidationParameter = {[key: string]: any}; - /** * Run validator functions on inputs. * diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index 58315ae8..ee638d3e 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -1,3 +1,4 @@ +import { ViewVariable } from "../../types/webserver.ts"; import { Logger } from "../../core/logger.ts"; import { Inflector } from "../../utility/inflector.ts"; import { Handlebars } from "../renderers/handlebars.ts"; @@ -8,10 +9,6 @@ import { Component } from "./component.ts"; import { Registry } from "../../utility/registry.ts"; import { compress as compressBrotli } from "https://deno.land/x/brotli@v0.1.4/mod.ts"; -export interface ViewVariable { - [key: string]: string | number | unknown; -} - export class Controller { private static readonly _templateDir = `./src/templates`; private static readonly _componentDir = `file:///${Deno.cwd()}/src/controller/component`; diff --git a/webserver/http/request.ts b/webserver/http/request.ts index 2487d529..613eae0c 100644 --- a/webserver/http/request.ts +++ b/webserver/http/request.ts @@ -1,13 +1,6 @@ +import { RequestParameters, QueryParameters } from "../../types/webserver.ts"; import { Route } from "../routing/route.ts"; -export interface RequestParameters { - [name: string]: string; -} - -export interface QueryParameters { - [name: string]: string; -} - export class Request { constructor( private readonly url: string, diff --git a/webserver/http/response-builder.ts b/webserver/http/response-builder.ts index a6e36f30..5ad4fa14 100644 --- a/webserver/http/response-builder.ts +++ b/webserver/http/response-builder.ts @@ -1,10 +1,7 @@ +import { ResponseHeader } from "../../types/webserver.ts"; import { StatusCodes } from "./status-codes.ts"; import { TimeString } from "../../utility/time-string.ts"; -interface ResponseHeader { - [key: string]: string; -} - export class ResponseBuilder { private readonly _headers: Map> = new Map>(); private _status: StatusCodes = StatusCodes.OK; diff --git a/webserver/pathToRegexp.ts b/webserver/pathToRegexp.ts index c8be6514..74df45c6 100644 --- a/webserver/pathToRegexp.ts +++ b/webserver/pathToRegexp.ts @@ -1,19 +1,15 @@ -/** - * Tokenizer results. - */ -interface LexToken { - type: - | "OPEN" - | "CLOSE" - | "PATTERN" - | "NAME" - | "CHAR" - | "ESCAPED_CHAR" - | "MODIFIER" - | "END"; - index: number; - value: string; -} +import { + LexToken, + RegexpToFunctionOptions, + MatchFunction, + Key, + Token, + TokensToRegexpOptions, + Path, + PathFunction, + TokensToFunctionOptions, + ParseOptions +} from "../types/webserver.ts"; /** * Tokenize input string. @@ -123,17 +119,6 @@ function lexer(str: string): LexToken[] { return tokens; } -export interface ParseOptions { - /** - * Set the default delimiter for repeat parameters. (default: `'/'`) - */ - delimiter?: string; - /** - * List of characters to automatically consider prefixes when parsing. - */ - prefixes?: string; -} - /** * Parse a string for the raw tokens. */ @@ -231,21 +216,6 @@ export function parse(str: string, options: ParseOptions = {}): Token[] { return result; } -export interface TokensToFunctionOptions { - /** - * When `true` the regexp will be case sensitive. (default: `false`) - */ - sensitive?: boolean; - /** - * Function for encoding input strings for output. - */ - encode?: (value: string, token: Key) => string; - /** - * When `false` the function can produce an invalid (unmatched) path. (default: `true`) - */ - validate?: boolean; -} - /** * Compile a string to a template function for the path. */ @@ -256,8 +226,6 @@ export function compile

( return tokensToFunction

(parse(str, options), options); } -export type PathFunction

= (data?: P) => string; - /** * Expose a method for transforming tokens into the path function. */ @@ -342,34 +310,6 @@ export function tokensToFunction

( }; } -export interface RegexpToFunctionOptions { - /** - * Function for decoding strings for params. - */ - decode?: (value: string, token: Key) => string; -} - -/** - * A match result contains data about the path match. - */ -export interface MatchResult

{ - path: string; - index: number; - params: P; -} - -/** - * A match is either `false` (no match) or a match result. - */ -export type Match

= false | MatchResult

; - -/** - * The match function takes a string and returns whether it matched the path. - */ -export type MatchFunction

= ( - path: string, -) => Match

; - /** * Create path match function from `path-to-regexp` spec. */ @@ -432,22 +372,6 @@ function flags(options?: { sensitive?: boolean }) { return options && options.sensitive ? "" : "i"; } -/** - * Metadata about a key. - */ -export interface Key { - name: string | number; - prefix: string; - suffix: string; - pattern: string; - modifier: string; -} - -/** - * A token is a string (nothing special) or key metadata (capture group). - */ -export type Token = string | Key; - /** * Pull out keys from a regexp. */ @@ -496,37 +420,6 @@ function stringToRegexp( return tokensToRegexp(parse(path, options), keys, options); } -export interface TokensToRegexpOptions { - /** - * When `true` the regexp will be case sensitive. (default: `false`) - */ - sensitive?: boolean; - /** - * When `true` the regexp won't allow an optional trailing delimiter to match. (default: `false`) - */ - strict?: boolean; - /** - * When `true` the regexp will match to the end of the string. (default: `true`) - */ - end?: boolean; - /** - * When `true` the regexp will match from the beginning of the string. (default: `true`) - */ - start?: boolean; - /** - * Sets the final character for non-ending optimistic matches. (default: `/`) - */ - delimiter?: string; - /** - * List of characters that can also be "end" characters. - */ - endsWith?: string; - /** - * Encode path tokens for use in the `RegExp`. - */ - encode?: (value: string) => string; -} - /** * Expose a function for taking tokens and returning a RegExp. */ @@ -595,11 +488,6 @@ export function tokensToRegexp( return new RegExp(route, flags(options)); } -/** - * Supported `path-to-regexp` input types. - */ -export type Path = string | RegExp | Array; - /** * Normalize the given path string, returning a regular expression. * diff --git a/webserver/registry/registry.ts b/webserver/registry/registry.ts index 999e76b7..aac61316 100644 --- a/webserver/registry/registry.ts +++ b/webserver/registry/registry.ts @@ -1,6 +1,4 @@ -interface RegistryItem { - [key: string]: any; -} +import { RegistryItem } from "../../types/webserver.ts"; /** * @deprecated Use {@linkcode ../../utility/Registry} instead diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index 0d537fcf..39f6f5d0 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -1,14 +1,9 @@ +import { HandlebarsCacheItem, ViewVariable } from "../../types/webserver.ts"; import { default as hbs } from "https://jspm.dev/handlebars@4.7.6"; import { raise } from "../../error/raise.ts"; -import { ViewVariable } from "../controller/controller.ts"; - -interface CacheItem { - // deno-lint-ignore ban-types -- TODO - [key: string]: Function; -} export class Handlebars { - private static _cache: CacheItem = {}; + private static _cache: HandlebarsCacheItem = {}; public static async render( path: string, diff --git a/webserver/routing/router.ts b/webserver/routing/router.ts index dd0b04f3..bef1ab38 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -1,22 +1,16 @@ +import { Route, QueryParameters, RequestParameters } from "../../types/webserver.ts"; import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts"; import { readAll } from "https://deno.land/std@0.213.0/io/read_all.ts"; import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../utility/inflector.ts"; import { Logger } from "../../core/logger.ts"; -import { QueryParameters, Request as ChompRequest, RequestParameters } from "../http/request.ts"; +import { Request as ChompRequest } from "../http/request.ts"; import { StatusCodes } from "../http/status-codes.ts"; import { Route as ChompRoute } from "./route.ts"; import { Controller } from "../controller/controller.ts"; import { Registry } from "../../utility/registry.ts"; import { raise } from "../../error/raise.ts"; -interface Route { - path: string; - controller: string; - action: string; - method?: string; -} - export class Router { private static readonly _controllerDir = `file://${Deno.cwd()}/src/controller`; private static routes: ChompRoute[] = []; diff --git a/websocket/events.ts b/websocket/events.ts index a91c4a6a..759bfd09 100644 --- a/websocket/events.ts +++ b/websocket/events.ts @@ -1,10 +1,6 @@ +import { IEvent } from "../types/websocket.ts"; import { Logger } from "../core/logger.ts"; -interface IEvent { - name: string; - handler: string; -} - export class Events { private static list: IEvent[] = []; // deno-lint-ignore no-explicit-any -- TODO diff --git a/websocket/websocket.ts b/websocket/websocket.ts index 393ecb09..2161f3a9 100644 --- a/websocket/websocket.ts +++ b/websocket/websocket.ts @@ -4,6 +4,12 @@ import { Events } from "./events.ts"; import { Authenticator } from "./authenticator.ts"; import { Configure } from "../core/configure.ts"; +declare global { + interface Window { + websocket: Websocket; + } +} + export class Websocket { private readonly port: number = 80; private readonly authenticate: boolean = false; From cfe454d04d585e8754790058dc8c39055b6f11fa Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 14:37:44 +0100 Subject: [PATCH 349/379] Turn Webserver Registry into Proxy to the new Registry --- types/webserver.ts | 4 ---- webserver/registry/registry.ts | 13 ++++++------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/types/webserver.ts b/types/webserver.ts index 90e3e268..32499b50 100644 --- a/types/webserver.ts +++ b/types/webserver.ts @@ -14,10 +14,6 @@ export interface ResponseHeader { [key: string]: string; } -export interface RegistryItem { - [key: string]: any; -} - export interface HandlebarsCacheItem { // deno-lint-ignore ban-types -- TODO [key: string]: Function; diff --git a/webserver/registry/registry.ts b/webserver/registry/registry.ts index aac61316..736377f8 100644 --- a/webserver/registry/registry.ts +++ b/webserver/registry/registry.ts @@ -1,11 +1,10 @@ -import { RegistryItem } from "../../types/webserver.ts"; +import { Registry as newRegistry } from "../../utility/registry.ts"; /** - * @deprecated Use {@linkcode ../../utility/Registry} instead + * @deprecated Use {@linkcode ../../utility/Registry} instead. + * This class only serves as a legacy proxy to it. */ export class Registry { - private static _items: RegistryItem = {}; - /** * Add an item to the registry * @@ -13,7 +12,7 @@ export class Registry { * @param module */ public static add(name: string, module: any): void { - Registry._items[name] = module; + newRegistry.add(name, module); } /** @@ -22,7 +21,7 @@ export class Registry { * @param name */ public static get(name: string): any | null { - return Registry._items[name] ?? null; + return newRegistry.get(name); } /** @@ -31,6 +30,6 @@ export class Registry { * @param name */ public static has(name: string): boolean { - return name in Registry._items; + return newRegistry.has(name); } } From 1038c84a1772b728087c14ec7e3a2b1f85dddf57 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 15:13:38 +0100 Subject: [PATCH 350/379] Significantly cleanup Webserver --- types/webserver.ts | 2 ++ webserver/controller/controller.ts | 17 +++++----- webserver/renderers/handlebars.ts | 51 ++++++++++++++++++++--------- webserver/renderers/json.ts | 15 +++++++++ webserver/renderers/mod.ts | 3 ++ webserver/renderers/octet-stream.ts | 15 +++++++++ webserver/renderers/plaintext.ts | 15 +++++++++ 7 files changed, 95 insertions(+), 23 deletions(-) create mode 100644 webserver/renderers/json.ts create mode 100644 webserver/renderers/octet-stream.ts create mode 100644 webserver/renderers/plaintext.ts diff --git a/types/webserver.ts b/types/webserver.ts index 32499b50..a674f7bc 100644 --- a/types/webserver.ts +++ b/types/webserver.ts @@ -2,6 +2,8 @@ export interface ViewVariable { [key: string]: string | number | unknown; } +export type ViewVariables = Map; + export interface RequestParameters { [name: string]: string; } diff --git a/webserver/controller/controller.ts b/webserver/controller/controller.ts index ee638d3e..17a1f9ac 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -1,19 +1,20 @@ -import { ViewVariable } from "../../types/webserver.ts"; +import {ViewVariables} from "../../types/webserver.ts"; import { Logger } from "../../core/logger.ts"; import { Inflector } from "../../utility/inflector.ts"; -import { Handlebars } from "../renderers/handlebars.ts"; +import {Handlebars, Json, OctetStream, Plaintext} from "../renderers/mod.ts"; import { ResponseBuilder } from "../http/response-builder.ts"; import { Request } from "../http/request.ts"; import { raise } from "../../error/raise.ts"; import { Component } from "./component.ts"; import { Registry } from "../../utility/registry.ts"; import { compress as compressBrotli } from "https://deno.land/x/brotli@v0.1.4/mod.ts"; +import {valueOrDefault} from "../../utility/value-or-default.ts"; export class Controller { private static readonly _templateDir = `./src/templates`; private static readonly _componentDir = `file:///${Deno.cwd()}/src/controller/component`; private _response: ResponseBuilder = new ResponseBuilder(); - private _vars: ViewVariable = {}; + private _vars: ViewVariables = new Map(); /** * Set the 'Content-Type' header @@ -102,7 +103,7 @@ export class Controller { * @param value */ protected set(key: string, value: string | number | unknown) { - this._vars[key] = value; + this._vars.set(key, value); } /** @@ -116,22 +117,22 @@ export class Controller { const canCompress = true; switch (this.getResponse().getHeaderLine("Content-Type").toLowerCase()) { case "application/json": { - body = JSON.stringify(this._vars["data"]); + body = Json.render(this._vars); break; } case "text/plain": { - body = this._vars["message"] as string; + body = Plaintext.render(this._vars); break; } case "text/html": { const controller = Inflector.lcfirst(this.getRequest().getRoute().getController()); const action = this.getRequest().getRoute().getAction(); const rendered = await Handlebars.render(`${Controller._templateDir}/${controller}/${action}.hbs`, this._vars); - body = rendered ? rendered : ''; + body = valueOrDefault(rendered, ''); break; } case "application/octet-stream": { - body = this._vars["data"] as Uint8Array; + body = OctetStream.render(this._vars); break; } } diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index 39f6f5d0..2fb7516c 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -1,33 +1,54 @@ -import { HandlebarsCacheItem, ViewVariable } from "../../types/webserver.ts"; +import { HandlebarsCacheItem, ViewVariables } from "../../types/webserver.ts"; import { default as hbs } from "https://jspm.dev/handlebars@4.7.6"; -import { raise } from "../../error/raise.ts"; +import { Cache } from "../../core/cache.ts"; export class Handlebars { - private static _cache: HandlebarsCacheItem = {}; + /** + * Render the Handlebars template + * + * @param path + * @param vars + * @param expiry Time to cache the rendered template. Use null to cache indefinitely. + */ public static async render( path: string, - vars: ViewVariable = {}, - cache = true, - ): Promise { - // Read and execute from cache if possible - if (cache && path in Handlebars._cache) return Handlebars._cache[path](vars); + vars: ViewVariables = new Map(), + expiry: string|null = "+1 hour", + ): Promise { + // Load and compile template + const template = await Handlebars._compileTemplate(path, expiry); + + // Render template with our view vars + return template(vars); + } + + public static async _compileTemplate(path: string, expiry: string|null = "+1 hour") { + // Build Cache key + const key = `Webserver.Rendered.Handlebars "${path}"`; + + // Check if we have a cached version + // Return it if we do + const inCache = Cache.exists(key); + const isValid = !Cache.expired(key); + if(inCache && isValid) return Cache.get(key); // Load our template - const template = await Handlebars.getTemplate(path) ?? raise("Could not load template"); + const template = await Handlebars._getTemplate(path); // Compile our template - // Cache it if need be // TODO: Fix type // @ts-ignore See TODO - const compiled = hbs.compile(template) ?? raise("Could not compile template"); - if (cache) Handlebars._cache[path] = compiled; + const compiled = hbs.compile(template); + + // Cache template + Cache.set(key, compiled, expiry) - // Let the engine render - return compiled(vars); + // Return compiled template + return compiled; } - private static async getTemplate(path: string): Promise { + private static async _getTemplate(path: string): Promise { // Make sure out template exists try { await Deno.stat(path); diff --git a/webserver/renderers/json.ts b/webserver/renderers/json.ts new file mode 100644 index 00000000..95a4c8e5 --- /dev/null +++ b/webserver/renderers/json.ts @@ -0,0 +1,15 @@ +import {ViewVariables} from "../../types/webserver.ts"; + +export class Json { + public static render( + vars: ViewVariables = new Map(), + ) { + // Check if vars contains a data object + // If not, return empty object + const hasData = vars.has('data'); + if(!hasData) return JSON.stringify({}); + + // Return stringified data + return JSON.stringify(vars.get('data')); + } +} diff --git a/webserver/renderers/mod.ts b/webserver/renderers/mod.ts index 00d63ff9..c7fd1955 100644 --- a/webserver/renderers/mod.ts +++ b/webserver/renderers/mod.ts @@ -1 +1,4 @@ export * from "./handlebars.ts"; +export * from "./json.ts"; +export * from "./octet-stream.ts"; +export * from "./plaintext.ts"; diff --git a/webserver/renderers/octet-stream.ts b/webserver/renderers/octet-stream.ts new file mode 100644 index 00000000..001ea449 --- /dev/null +++ b/webserver/renderers/octet-stream.ts @@ -0,0 +1,15 @@ +import {ViewVariables} from "../../types/webserver.ts"; + +export class OctetStream { + public static render( + vars: ViewVariables = new Map(), + ): Uint8Array { + // Check if vars contains a data object + // If not, return empty array + const hasData = vars.has('data'); + if(!hasData) return new Uint8Array(); + + // Return stringified data + return vars.get('data'); + } +} diff --git a/webserver/renderers/plaintext.ts b/webserver/renderers/plaintext.ts new file mode 100644 index 00000000..a1f9ca38 --- /dev/null +++ b/webserver/renderers/plaintext.ts @@ -0,0 +1,15 @@ +import {ViewVariables} from "../../types/webserver.ts"; + +export class Plaintext { + public static render( + vars: ViewVariables = new Map(), + ): string { + // Check if vars contains a data object + // If not, return empty string + const hasData = vars.has('message'); + if(!hasData) return ''; + + // Return stringified data + return vars.get('message'); + } +} From 478858c8c83d68ee7b2baa8028838f31e32aeae7 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 15:15:42 +0100 Subject: [PATCH 351/379] Cleanup some types --- types/webserver.ts | 9 --------- webserver/renderers/handlebars.ts | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/types/webserver.ts b/types/webserver.ts index a674f7bc..8080b61e 100644 --- a/types/webserver.ts +++ b/types/webserver.ts @@ -1,7 +1,3 @@ -export interface ViewVariable { - [key: string]: string | number | unknown; -} - export type ViewVariables = Map; export interface RequestParameters { @@ -16,11 +12,6 @@ export interface ResponseHeader { [key: string]: string; } -export interface HandlebarsCacheItem { - // deno-lint-ignore ban-types -- TODO - [key: string]: Function; -} - export interface Route { path: string; controller: string; diff --git a/webserver/renderers/handlebars.ts b/webserver/renderers/handlebars.ts index 2fb7516c..47c1eb19 100644 --- a/webserver/renderers/handlebars.ts +++ b/webserver/renderers/handlebars.ts @@ -1,4 +1,4 @@ -import { HandlebarsCacheItem, ViewVariables } from "../../types/webserver.ts"; +import { ViewVariables } from "../../types/webserver.ts"; import { default as hbs } from "https://jspm.dev/handlebars@4.7.6"; import { Cache } from "../../core/cache.ts"; From ad300a3ba17f834266c3753bf4a9f620ff22865b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 22:59:54 +0100 Subject: [PATCH 352/379] Remove generated docs --- .gitignore | 3 + docs/all_symbols.html | 348 -- docs/fuse.js | 11 - docs/index.html | 65 - docs/page.css | 1 - docs/script.js | 33 - docs/search.js | 168 - docs/search_index.js | 3 - docs/styles.css | 1 - docs/~/Algorithms.html | 1228 ------ docs/~/Authenticator.client.html | 253 -- docs/~/Authenticator.html | 157 - docs/~/Authenticator.prototype.html | 1 - docs/~/Cache._items.html | 156 - docs/~/Cache.consume.html | 372 -- docs/~/Cache.dump.html | 243 -- docs/~/Cache.exists.html | 319 -- docs/~/Cache.expired.html | 318 -- docs/~/Cache.get.html | 412 -- docs/~/Cache.html | 602 --- docs/~/Cache.prototype.html | 1 - docs/~/Cache.remove.html | 318 -- docs/~/Cache.set.html | 427 --- docs/~/Cache.sweep.html | 243 -- docs/~/CheckSource.html | 679 ---- docs/~/CheckSource.prototype.addFile.html | 252 -- docs/~/CheckSource.prototype.checkFiles.html | 176 - docs/~/CheckSource.prototype.errors.html | 156 - docs/~/CheckSource.prototype.files.html | 156 - docs/~/CheckSource.prototype.getFiles.html | 253 -- docs/~/CheckSource.prototype.html | 1 - docs/~/CheckSource.prototype.run.html | 175 - docs/~/Configure.check.html | 321 -- docs/~/Configure.clear.html | 246 -- docs/~/Configure.config.html | 156 - docs/~/Configure.consume.html | 415 --- docs/~/Configure.delete.html | 321 -- docs/~/Configure.dump.html | 245 -- docs/~/Configure.get.html | 418 --- docs/~/Configure.hasLoaded.html | 156 - docs/~/Configure.html | 705 ---- docs/~/Configure.load.html | 321 -- docs/~/Configure.prototype.html | 1 - docs/~/Configure.reset.html | 245 -- docs/~/Configure.set.html | 373 -- docs/~/Controller._componentDir.html | 156 - docs/~/Controller._templateDir.html | 156 - docs/~/Controller.html | 813 ---- docs/~/Controller.prototype._response.html | 156 - docs/~/Controller.prototype._vars.html | 156 - docs/~/Controller.prototype.getRequest.html | 176 - docs/~/Controller.prototype.getResponse.html | 176 - docs/~/Controller.prototype.html | 1 - docs/~/Controller.prototype.initialize.html | 177 - .../~/Controller.prototype.loadComponent.html | 251 -- docs/~/Controller.prototype.render.html | 178 - docs/~/Controller.prototype.set.html | 303 -- docs/~/Controller.prototype.type.html | 255 -- docs/~/CouchDB.html | 739 ---- docs/~/CouchDB.prototype.auth.html | 156 - docs/~/CouchDB.prototype.delete.html | 384 -- docs/~/CouchDB.prototype.get.html | 328 -- docs/~/CouchDB.prototype.html | 1 - docs/~/CouchDB.prototype.insert.html | 336 -- docs/~/CouchDB.prototype.password.html | 321 -- docs/~/CouchDB.prototype.raw.html | 419 --- docs/~/CouchDB.prototype.update.html | 432 --- docs/~/CouchDB.prototype.upsert.html | 381 -- docs/~/CouchDB.prototype.username.html | 321 -- docs/~/CouchDB.prototype.viewDesign.html | 428 --- docs/~/Cron.Cron.html | 81 - docs/~/Cron.html | 379 -- docs/~/DEFAULT_OPTS.html | 158 - docs/~/Druid.html | 415 --- docs/~/Druid.prototype.create.html | 177 - docs/~/Druid.prototype.getSpec.html | 175 - docs/~/Druid.prototype.html | 1 - docs/~/Druid.prototype.setSpec.html | 251 -- docs/~/Druid.prototype.spec.html | 156 - docs/~/ErrorCodes.html | 1074 ------ docs/~/Events.add.html | 251 -- docs/~/Events.dispatch.html | 252 -- docs/~/Events.getEvents.html | 124 - docs/~/Events.getHandler.html | 200 - docs/~/Events.handlers.html | 156 - docs/~/Events.html | 438 --- docs/~/Events.list.html | 156 - docs/~/Events.prototype.html | 1 - docs/~/ExclusionConfig.directories.html | 156 - docs/~/ExclusionConfig.files.html | 156 - docs/~/ExclusionConfig.html | 209 -- docs/~/File.html | 488 --- docs/~/File.prototype.create.html | 175 - docs/~/File.prototype.delete.html | 175 - docs/~/File.prototype.exists.html | 175 - docs/~/File.prototype.ext.html | 175 - docs/~/File.prototype.html | 1 - docs/~/File.prototype.readFile.html | 124 - docs/~/File.prototype.readTextFile.html | 124 - docs/~/Folder.html | 286 -- docs/~/Folder.prototype.create.html | 254 -- docs/~/Folder.prototype.exists.html | 176 - docs/~/Folder.prototype.html | 1 - docs/~/GraphQL.html | 466 --- docs/~/GraphQL.prototype._query.html | 156 - docs/~/GraphQL.prototype._variables.html | 79 - docs/~/GraphQL.prototype.addVariable.html | 304 -- docs/~/GraphQL.prototype.execute.html | 124 - docs/~/GraphQL.prototype.html | 1 - docs/~/GraphQL.prototype.setQuery.html | 253 -- docs/~/Hash.html | 363 -- docs/~/Hash.prototype.digest.html | 289 -- docs/~/Hash.prototype.hex.html | 195 - docs/~/Hash.prototype.html | 1 - docs/~/Hash.prototype.result.html | 156 - docs/~/INSECURE_ALGORITHMS.html | 157 - docs/~/Inflector.camelize.html | 305 -- docs/~/Inflector.html | 367 -- docs/~/Inflector.humanize.html | 305 -- docs/~/Inflector.lcfirst.html | 252 -- docs/~/Inflector.pascalize.html | 305 -- docs/~/Inflector.prototype.html | 1 - docs/~/Inflector.ucfirst.html | 252 -- docs/~/InfluxDB.html | 362 -- docs/~/InfluxDB.prototype._api.html | 156 - docs/~/InfluxDB.prototype.html | 1 - docs/~/InfluxDB.prototype.setApi.html | 354 -- docs/~/InfluxDB.prototype.write.html | 252 -- docs/~/Logger._handlers.html | 156 - docs/~/Logger.debug.html | 254 -- docs/~/Logger.error.html | 307 -- docs/~/Logger.html | 499 --- docs/~/Logger.info.html | 253 -- docs/~/Logger.prototype.html | 1 - docs/~/Logger.setHandler.html | 305 -- docs/~/Logger.time.html | 180 - docs/~/Logger.warning.html | 253 -- docs/~/Loki.html | 234 -- docs/~/Loki.prototype.html | 1 - docs/~/Loki.prototype.send.html | 252 -- docs/~/Ntfy.html | 234 -- docs/~/Ntfy.prototype.html | 1 - docs/~/Ntfy.prototype.send.html | 252 -- docs/~/Nut.html | 1083 ------ docs/~/Nut.prototype.UPSList.html | 124 - docs/~/Nut.prototype._status.html | 156 - docs/~/Nut.prototype.callback.html | 156 - docs/~/Nut.prototype.client.html | 156 - docs/~/Nut.prototype.close.html | 175 - docs/~/Nut.prototype.connect.html | 175 - docs/~/Nut.prototype.dataBuf.html | 156 - docs/~/Nut.prototype.getCharge.html | 251 -- docs/~/Nut.prototype.getLoad.html | 251 -- docs/~/Nut.prototype.getPowerLimit.html | 251 -- docs/~/Nut.prototype.getRuntime.html | 251 -- docs/~/Nut.prototype.getStatus.html | 251 -- docs/~/Nut.prototype.host.html | 156 - docs/~/Nut.prototype.html | 1 - docs/~/Nut.prototype.onReceive.html | 175 - docs/~/Nut.prototype.port.html | 156 - docs/~/Nut.prototype.send.html | 302 -- docs/~/Nut.prototype.status.html | 175 - docs/~/PASSWORD_DEFAULT.html | 81 - docs/~/Password.doHash.html | 404 -- docs/~/Password.hash.html | 357 -- docs/~/Password.html | 260 -- docs/~/Password.prototype.html | 1 - docs/~/Password.verify.html | 305 -- docs/~/PasswordOptions.allowInsecure.html | 156 - docs/~/PasswordOptions.cost.html | 156 - docs/~/PasswordOptions.html | 210 -- docs/~/QueryParameters.html | 128 - docs/~/Queue.html | 735 ---- docs/~/Queue.prototype.add.html | 253 -- docs/~/Queue.prototype.clear.html | 177 - docs/~/Queue.prototype.contains.html | 253 -- docs/~/Queue.prototype.count.html | 177 - docs/~/Queue.prototype.dump.html | 177 - docs/~/Queue.prototype.html | 1 - docs/~/Queue.prototype.isEmpty.html | 177 - docs/~/Queue.prototype.items.html | 156 - docs/~/Queue.prototype.next.html | 178 - docs/~/Queue.prototype.peek.html | 178 - docs/~/Queue.prototype.scheduler.html | 156 - docs/~/RCON.html | 445 --- docs/~/RCON.prototype.close.html | 177 - docs/~/RCON.prototype.conn.html | 156 - docs/~/RCON.prototype.connect.html | 356 -- docs/~/RCON.prototype.html | 1 - docs/~/RCON.prototype.recv.html | 177 - docs/~/RCON.prototype.send.html | 305 -- docs/~/RCON.prototype.sendSync.html | 307 -- docs/~/Random.bytes.html | 323 -- docs/~/Random.float.html | 474 --- docs/~/Random.html | 321 -- docs/~/Random.integer.html | 474 --- docs/~/Random.prototype.html | 1 - docs/~/Random.string.html | 323 -- docs/~/Redis.connect.html | 306 -- docs/~/Redis.connection.html | 156 - docs/~/Redis.getConnection.html | 177 - docs/~/Redis.html | 286 -- docs/~/Redis.prototype.html | 1 - docs/~/Request.html | 743 ---- docs/~/Request.prototype.getAuth.html | 175 - docs/~/Request.prototype.getBody.html | 175 - docs/~/Request.prototype.getHeaders.html | 175 - docs/~/Request.prototype.getIp.html | 175 - docs/~/Request.prototype.getMethod.html | 175 - docs/~/Request.prototype.getParam.html | 251 -- docs/~/Request.prototype.getParams.html | 175 - docs/~/Request.prototype.getQuery.html | 251 -- docs/~/Request.prototype.getQueryParams.html | 175 - docs/~/Request.prototype.getRoute.html | 175 - docs/~/Request.prototype.getUrl.html | 175 - docs/~/Request.prototype.html | 1 - docs/~/RequestParameters.html | 128 - docs/~/Router._controllerDir.html | 156 - docs/~/Router.add.html | 254 -- docs/~/Router.execute.html | 304 -- docs/~/Router.getAuth.html | 253 -- docs/~/Router.getBody.html | 253 -- docs/~/Router.getParams.html | 304 -- docs/~/Router.getQuery.html | 253 -- docs/~/Router.getRoutes.html | 124 - docs/~/Router.html | 651 ---- docs/~/Router.prototype.html | 1 - docs/~/Router.route.html | 201 - docs/~/Router.routes.html | 156 - docs/~/StatusCodes.html | 3318 ----------------- docs/~/Text.html | 262 -- docs/~/Text.htmlentities.html | 254 -- docs/~/Text.prototype.html | 1 - docs/~/Text.tokenize.html | 304 -- docs/~/Text.uuid.html | 176 - docs/~/Time.html | 983 ----- docs/~/Time.prototype.add.html | 200 - docs/~/Time.prototype.addDay.html | 201 - docs/~/Time.prototype.addWeek.html | 201 - docs/~/Time.prototype.format.html | 200 - docs/~/Time.prototype.getTime.html | 124 - docs/~/Time.prototype.hours.html | 124 - docs/~/Time.prototype.html | 1 - docs/~/Time.prototype.midnight.html | 124 - docs/~/Time.prototype.milliseconds.html | 124 - docs/~/Time.prototype.minutes.html | 124 - docs/~/Time.prototype.month.html | 124 - docs/~/Time.prototype.monthDay.html | 124 - docs/~/Time.prototype.seconds.html | 124 - docs/~/Time.prototype.time.html | 79 - docs/~/Time.prototype.weekDay.html | 124 - docs/~/Time.prototype.year.html | 124 - docs/~/TimeString.html | 370 -- docs/~/TimeStringSeconds.html | 370 -- docs/~/ViewVariable.html | 128 - docs/~/Webserver.html | 362 -- docs/~/Webserver.prototype.html | 1 - docs/~/Webserver.prototype.serve.html | 251 -- docs/~/Webserver.prototype.server.html | 156 - docs/~/Webserver.prototype.start.html | 175 - docs/~/Websocket.html | 571 --- docs/~/Websocket.prototype.authenticate.html | 156 - docs/~/Websocket.prototype.broadcast.html | 302 -- docs/~/Websocket.prototype.handleEvent.html | 252 -- docs/~/Websocket.prototype.html | 1 - docs/~/Websocket.prototype.onMessage.html | 251 -- docs/~/Websocket.prototype.port.html | 156 - docs/~/Websocket.prototype.server.html | 156 - docs/~/Websocket.prototype.start.html | 175 - docs/~/raise.html | 547 --- 270 files changed, 3 insertions(+), 65911 deletions(-) delete mode 100644 docs/all_symbols.html delete mode 100644 docs/fuse.js delete mode 100644 docs/index.html delete mode 100644 docs/page.css delete mode 100644 docs/script.js delete mode 100644 docs/search.js delete mode 100644 docs/search_index.js delete mode 100644 docs/styles.css delete mode 100644 docs/~/Algorithms.html delete mode 100644 docs/~/Authenticator.client.html delete mode 100644 docs/~/Authenticator.html delete mode 100644 docs/~/Authenticator.prototype.html delete mode 100644 docs/~/Cache._items.html delete mode 100644 docs/~/Cache.consume.html delete mode 100644 docs/~/Cache.dump.html delete mode 100644 docs/~/Cache.exists.html delete mode 100644 docs/~/Cache.expired.html delete mode 100644 docs/~/Cache.get.html delete mode 100644 docs/~/Cache.html delete mode 100644 docs/~/Cache.prototype.html delete mode 100644 docs/~/Cache.remove.html delete mode 100644 docs/~/Cache.set.html delete mode 100644 docs/~/Cache.sweep.html delete mode 100644 docs/~/CheckSource.html delete mode 100644 docs/~/CheckSource.prototype.addFile.html delete mode 100644 docs/~/CheckSource.prototype.checkFiles.html delete mode 100644 docs/~/CheckSource.prototype.errors.html delete mode 100644 docs/~/CheckSource.prototype.files.html delete mode 100644 docs/~/CheckSource.prototype.getFiles.html delete mode 100644 docs/~/CheckSource.prototype.html delete mode 100644 docs/~/CheckSource.prototype.run.html delete mode 100644 docs/~/Configure.check.html delete mode 100644 docs/~/Configure.clear.html delete mode 100644 docs/~/Configure.config.html delete mode 100644 docs/~/Configure.consume.html delete mode 100644 docs/~/Configure.delete.html delete mode 100644 docs/~/Configure.dump.html delete mode 100644 docs/~/Configure.get.html delete mode 100644 docs/~/Configure.hasLoaded.html delete mode 100644 docs/~/Configure.html delete mode 100644 docs/~/Configure.load.html delete mode 100644 docs/~/Configure.prototype.html delete mode 100644 docs/~/Configure.reset.html delete mode 100644 docs/~/Configure.set.html delete mode 100644 docs/~/Controller._componentDir.html delete mode 100644 docs/~/Controller._templateDir.html delete mode 100644 docs/~/Controller.html delete mode 100644 docs/~/Controller.prototype._response.html delete mode 100644 docs/~/Controller.prototype._vars.html delete mode 100644 docs/~/Controller.prototype.getRequest.html delete mode 100644 docs/~/Controller.prototype.getResponse.html delete mode 100644 docs/~/Controller.prototype.html delete mode 100644 docs/~/Controller.prototype.initialize.html delete mode 100644 docs/~/Controller.prototype.loadComponent.html delete mode 100644 docs/~/Controller.prototype.render.html delete mode 100644 docs/~/Controller.prototype.set.html delete mode 100644 docs/~/Controller.prototype.type.html delete mode 100644 docs/~/CouchDB.html delete mode 100644 docs/~/CouchDB.prototype.auth.html delete mode 100644 docs/~/CouchDB.prototype.delete.html delete mode 100644 docs/~/CouchDB.prototype.get.html delete mode 100644 docs/~/CouchDB.prototype.html delete mode 100644 docs/~/CouchDB.prototype.insert.html delete mode 100644 docs/~/CouchDB.prototype.password.html delete mode 100644 docs/~/CouchDB.prototype.raw.html delete mode 100644 docs/~/CouchDB.prototype.update.html delete mode 100644 docs/~/CouchDB.prototype.upsert.html delete mode 100644 docs/~/CouchDB.prototype.username.html delete mode 100644 docs/~/CouchDB.prototype.viewDesign.html delete mode 100644 docs/~/Cron.Cron.html delete mode 100644 docs/~/Cron.html delete mode 100644 docs/~/DEFAULT_OPTS.html delete mode 100644 docs/~/Druid.html delete mode 100644 docs/~/Druid.prototype.create.html delete mode 100644 docs/~/Druid.prototype.getSpec.html delete mode 100644 docs/~/Druid.prototype.html delete mode 100644 docs/~/Druid.prototype.setSpec.html delete mode 100644 docs/~/Druid.prototype.spec.html delete mode 100644 docs/~/ErrorCodes.html delete mode 100644 docs/~/Events.add.html delete mode 100644 docs/~/Events.dispatch.html delete mode 100644 docs/~/Events.getEvents.html delete mode 100644 docs/~/Events.getHandler.html delete mode 100644 docs/~/Events.handlers.html delete mode 100644 docs/~/Events.html delete mode 100644 docs/~/Events.list.html delete mode 100644 docs/~/Events.prototype.html delete mode 100644 docs/~/ExclusionConfig.directories.html delete mode 100644 docs/~/ExclusionConfig.files.html delete mode 100644 docs/~/ExclusionConfig.html delete mode 100644 docs/~/File.html delete mode 100644 docs/~/File.prototype.create.html delete mode 100644 docs/~/File.prototype.delete.html delete mode 100644 docs/~/File.prototype.exists.html delete mode 100644 docs/~/File.prototype.ext.html delete mode 100644 docs/~/File.prototype.html delete mode 100644 docs/~/File.prototype.readFile.html delete mode 100644 docs/~/File.prototype.readTextFile.html delete mode 100644 docs/~/Folder.html delete mode 100644 docs/~/Folder.prototype.create.html delete mode 100644 docs/~/Folder.prototype.exists.html delete mode 100644 docs/~/Folder.prototype.html delete mode 100644 docs/~/GraphQL.html delete mode 100644 docs/~/GraphQL.prototype._query.html delete mode 100644 docs/~/GraphQL.prototype._variables.html delete mode 100644 docs/~/GraphQL.prototype.addVariable.html delete mode 100644 docs/~/GraphQL.prototype.execute.html delete mode 100644 docs/~/GraphQL.prototype.html delete mode 100644 docs/~/GraphQL.prototype.setQuery.html delete mode 100644 docs/~/Hash.html delete mode 100644 docs/~/Hash.prototype.digest.html delete mode 100644 docs/~/Hash.prototype.hex.html delete mode 100644 docs/~/Hash.prototype.html delete mode 100644 docs/~/Hash.prototype.result.html delete mode 100644 docs/~/INSECURE_ALGORITHMS.html delete mode 100644 docs/~/Inflector.camelize.html delete mode 100644 docs/~/Inflector.html delete mode 100644 docs/~/Inflector.humanize.html delete mode 100644 docs/~/Inflector.lcfirst.html delete mode 100644 docs/~/Inflector.pascalize.html delete mode 100644 docs/~/Inflector.prototype.html delete mode 100644 docs/~/Inflector.ucfirst.html delete mode 100644 docs/~/InfluxDB.html delete mode 100644 docs/~/InfluxDB.prototype._api.html delete mode 100644 docs/~/InfluxDB.prototype.html delete mode 100644 docs/~/InfluxDB.prototype.setApi.html delete mode 100644 docs/~/InfluxDB.prototype.write.html delete mode 100644 docs/~/Logger._handlers.html delete mode 100644 docs/~/Logger.debug.html delete mode 100644 docs/~/Logger.error.html delete mode 100644 docs/~/Logger.html delete mode 100644 docs/~/Logger.info.html delete mode 100644 docs/~/Logger.prototype.html delete mode 100644 docs/~/Logger.setHandler.html delete mode 100644 docs/~/Logger.time.html delete mode 100644 docs/~/Logger.warning.html delete mode 100644 docs/~/Loki.html delete mode 100644 docs/~/Loki.prototype.html delete mode 100644 docs/~/Loki.prototype.send.html delete mode 100644 docs/~/Ntfy.html delete mode 100644 docs/~/Ntfy.prototype.html delete mode 100644 docs/~/Ntfy.prototype.send.html delete mode 100644 docs/~/Nut.html delete mode 100644 docs/~/Nut.prototype.UPSList.html delete mode 100644 docs/~/Nut.prototype._status.html delete mode 100644 docs/~/Nut.prototype.callback.html delete mode 100644 docs/~/Nut.prototype.client.html delete mode 100644 docs/~/Nut.prototype.close.html delete mode 100644 docs/~/Nut.prototype.connect.html delete mode 100644 docs/~/Nut.prototype.dataBuf.html delete mode 100644 docs/~/Nut.prototype.getCharge.html delete mode 100644 docs/~/Nut.prototype.getLoad.html delete mode 100644 docs/~/Nut.prototype.getPowerLimit.html delete mode 100644 docs/~/Nut.prototype.getRuntime.html delete mode 100644 docs/~/Nut.prototype.getStatus.html delete mode 100644 docs/~/Nut.prototype.host.html delete mode 100644 docs/~/Nut.prototype.html delete mode 100644 docs/~/Nut.prototype.onReceive.html delete mode 100644 docs/~/Nut.prototype.port.html delete mode 100644 docs/~/Nut.prototype.send.html delete mode 100644 docs/~/Nut.prototype.status.html delete mode 100644 docs/~/PASSWORD_DEFAULT.html delete mode 100644 docs/~/Password.doHash.html delete mode 100644 docs/~/Password.hash.html delete mode 100644 docs/~/Password.html delete mode 100644 docs/~/Password.prototype.html delete mode 100644 docs/~/Password.verify.html delete mode 100644 docs/~/PasswordOptions.allowInsecure.html delete mode 100644 docs/~/PasswordOptions.cost.html delete mode 100644 docs/~/PasswordOptions.html delete mode 100644 docs/~/QueryParameters.html delete mode 100644 docs/~/Queue.html delete mode 100644 docs/~/Queue.prototype.add.html delete mode 100644 docs/~/Queue.prototype.clear.html delete mode 100644 docs/~/Queue.prototype.contains.html delete mode 100644 docs/~/Queue.prototype.count.html delete mode 100644 docs/~/Queue.prototype.dump.html delete mode 100644 docs/~/Queue.prototype.html delete mode 100644 docs/~/Queue.prototype.isEmpty.html delete mode 100644 docs/~/Queue.prototype.items.html delete mode 100644 docs/~/Queue.prototype.next.html delete mode 100644 docs/~/Queue.prototype.peek.html delete mode 100644 docs/~/Queue.prototype.scheduler.html delete mode 100644 docs/~/RCON.html delete mode 100644 docs/~/RCON.prototype.close.html delete mode 100644 docs/~/RCON.prototype.conn.html delete mode 100644 docs/~/RCON.prototype.connect.html delete mode 100644 docs/~/RCON.prototype.html delete mode 100644 docs/~/RCON.prototype.recv.html delete mode 100644 docs/~/RCON.prototype.send.html delete mode 100644 docs/~/RCON.prototype.sendSync.html delete mode 100644 docs/~/Random.bytes.html delete mode 100644 docs/~/Random.float.html delete mode 100644 docs/~/Random.html delete mode 100644 docs/~/Random.integer.html delete mode 100644 docs/~/Random.prototype.html delete mode 100644 docs/~/Random.string.html delete mode 100644 docs/~/Redis.connect.html delete mode 100644 docs/~/Redis.connection.html delete mode 100644 docs/~/Redis.getConnection.html delete mode 100644 docs/~/Redis.html delete mode 100644 docs/~/Redis.prototype.html delete mode 100644 docs/~/Request.html delete mode 100644 docs/~/Request.prototype.getAuth.html delete mode 100644 docs/~/Request.prototype.getBody.html delete mode 100644 docs/~/Request.prototype.getHeaders.html delete mode 100644 docs/~/Request.prototype.getIp.html delete mode 100644 docs/~/Request.prototype.getMethod.html delete mode 100644 docs/~/Request.prototype.getParam.html delete mode 100644 docs/~/Request.prototype.getParams.html delete mode 100644 docs/~/Request.prototype.getQuery.html delete mode 100644 docs/~/Request.prototype.getQueryParams.html delete mode 100644 docs/~/Request.prototype.getRoute.html delete mode 100644 docs/~/Request.prototype.getUrl.html delete mode 100644 docs/~/Request.prototype.html delete mode 100644 docs/~/RequestParameters.html delete mode 100644 docs/~/Router._controllerDir.html delete mode 100644 docs/~/Router.add.html delete mode 100644 docs/~/Router.execute.html delete mode 100644 docs/~/Router.getAuth.html delete mode 100644 docs/~/Router.getBody.html delete mode 100644 docs/~/Router.getParams.html delete mode 100644 docs/~/Router.getQuery.html delete mode 100644 docs/~/Router.getRoutes.html delete mode 100644 docs/~/Router.html delete mode 100644 docs/~/Router.prototype.html delete mode 100644 docs/~/Router.route.html delete mode 100644 docs/~/Router.routes.html delete mode 100644 docs/~/StatusCodes.html delete mode 100644 docs/~/Text.html delete mode 100644 docs/~/Text.htmlentities.html delete mode 100644 docs/~/Text.prototype.html delete mode 100644 docs/~/Text.tokenize.html delete mode 100644 docs/~/Text.uuid.html delete mode 100644 docs/~/Time.html delete mode 100644 docs/~/Time.prototype.add.html delete mode 100644 docs/~/Time.prototype.addDay.html delete mode 100644 docs/~/Time.prototype.addWeek.html delete mode 100644 docs/~/Time.prototype.format.html delete mode 100644 docs/~/Time.prototype.getTime.html delete mode 100644 docs/~/Time.prototype.hours.html delete mode 100644 docs/~/Time.prototype.html delete mode 100644 docs/~/Time.prototype.midnight.html delete mode 100644 docs/~/Time.prototype.milliseconds.html delete mode 100644 docs/~/Time.prototype.minutes.html delete mode 100644 docs/~/Time.prototype.month.html delete mode 100644 docs/~/Time.prototype.monthDay.html delete mode 100644 docs/~/Time.prototype.seconds.html delete mode 100644 docs/~/Time.prototype.time.html delete mode 100644 docs/~/Time.prototype.weekDay.html delete mode 100644 docs/~/Time.prototype.year.html delete mode 100644 docs/~/TimeString.html delete mode 100644 docs/~/TimeStringSeconds.html delete mode 100644 docs/~/ViewVariable.html delete mode 100644 docs/~/Webserver.html delete mode 100644 docs/~/Webserver.prototype.html delete mode 100644 docs/~/Webserver.prototype.serve.html delete mode 100644 docs/~/Webserver.prototype.server.html delete mode 100644 docs/~/Webserver.prototype.start.html delete mode 100644 docs/~/Websocket.html delete mode 100644 docs/~/Websocket.prototype.authenticate.html delete mode 100644 docs/~/Websocket.prototype.broadcast.html delete mode 100644 docs/~/Websocket.prototype.handleEvent.html delete mode 100644 docs/~/Websocket.prototype.html delete mode 100644 docs/~/Websocket.prototype.onMessage.html delete mode 100644 docs/~/Websocket.prototype.port.html delete mode 100644 docs/~/Websocket.prototype.server.html delete mode 100644 docs/~/Websocket.prototype.start.html delete mode 100644 docs/~/raise.html diff --git a/.gitignore b/.gitignore index 25505de0..b48929bc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ # Ignore reports /coverage /cov.lcov + +# Ignore docs +/docs diff --git a/docs/all_symbols.html b/docs/all_symbols.html deleted file mode 100644 index faf5347c..00000000 --- a/docs/all_symbols.html +++ /dev/null @@ -1,348 +0,0 @@ - - - - All Symbols - Chomp documentation - - - - - - - - - - - - -

-
-
-
E
-
- Algorithms - -

List of algorithms supported by this library

-
-
-
c
-
- Authenticator - -
No documentation available
-
-
c
-
- Cache - -
No documentation available
-
-
c
-
- CheckSource - -

Check all files in the specified directories. -Doing this allows the program to start up significantly faster after deployment. -It is NOT a replacement for "deno lint".

-
-
-
c
-
- Configure - -
No documentation available
-
-
c
-
- Controller - -
No documentation available
-
-
c
-
- CouchDB - -
No documentation available
-
-
f
N
-
- Cron - -

Cron entrypoint

-
-
-
v
-
- Cron.Cron - -
No documentation available
-
-
v
-
- DEFAULT_OPTS - -

Default options for password hashing. -These defaults offer a good balance between performance and security.

-
-
-
c
-
- Druid - -
No documentation available
-
-
E
-
- ErrorCodes - -
No documentation available
-
-
c
-
- Events - -
No documentation available
-
-
I
-
- ExclusionConfig - -
No documentation available
-
-
c
-
- File - -
No documentation available
-
-
c
-
- Folder - -
No documentation available
-
-
c
-
- GraphQL - -
No documentation available
-
-
c
-
- Hash - -
No documentation available
-
-
c
-
- Inflector - -

Idea and code primarily based on CakePHP's code.

-
-
-
c
-
- InfluxDB - -
No documentation available
-
-
v
-
- INSECURE_ALGORITHMS - -

Specify algorithms that are supported but deemed insecure

-
-
-
c
-
- Logger - -
No documentation available
-
-
c
-
- Loki - -
No documentation available
-
-
c
-
- Ntfy - -
No documentation available
-
-
c
-
- Nut - -
No documentation available
-
-
c
-
- Password - -
No documentation available
-
-
v
-
- PASSWORD_DEFAULT - -

Recommended hashing algorithm for most use-cases. -May change over time to keep up with NIST approved algorithms

-
-
-
I
-
- PasswordOptions - -

Options for hashing a password

-
-
-
I
-
- QueryParameters - -
No documentation available
-
-
c
-
- Queue - -
No documentation available
-
-
f
-
- raise - -

Utility function that throws an error. -Band-aid for JS not supporting throwing in null-coalescing.

-
-
-
c
-
- Random - -
No documentation available
-
-
c
-
- RCON - -
No documentation available
-
-
c
-
- Redis - -
No documentation available
-
-
c
-
- Request - -
No documentation available
-
-
I
-
- RequestParameters - -
No documentation available
-
-
c
-
- Router - -
No documentation available
-
-
E
-
- StatusCodes - -
No documentation available
-
-
c
-
- Text - -
No documentation available
-
-
c
-
- Time - -
No documentation available
-
-
f
-
- TimeString - -

Takes a time string and turns it into milliseconds

-
-
-
f
-
- TimeStringSeconds - -

Takes a time string and turns it into round seconds

-
-
-
I
-
- ViewVariable - -
No documentation available
-
-
c
-
- Webserver - -
No documentation available
-
-
c
-
- Websocket - -
No documentation available
-
-
-
-
-
- - diff --git a/docs/fuse.js b/docs/fuse.js deleted file mode 100644 index a7eea4e3..00000000 --- a/docs/fuse.js +++ /dev/null @@ -1,11 +0,0 @@ -// deno-fmt-ignore-file -// deno-lint-ignore-file -/** - * Fuse.js v7.0.0 - Lightweight fuzzy-search (http://fusejs.io) - * - * Copyright (c) 2023 Kiro Risk (http://kiro.me) - * All Rights Reserved. Apache Software License 2.0 - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?$.getFn:n,o=t.fieldNormWeight,c=void 0===o?$.fieldNormWeight:o;r(this,e),this.norm=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(F).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),c=parseFloat(Math.round(o*r)/r);return n.set(i,c),c},clear:function(){n.clear()}}}(c,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,m(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();m(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?$.getFn:r,o=n.fieldNormWeight,c=void 0===o?$.fieldNormWeight:o,a=new R({getFn:i,fieldNormWeight:c});return a.setKeys(e.map(A)),a.setSources(t),a.create(),a}function N(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,c=t.expectedLocation,a=void 0===c?0:c,s=t.distance,u=void 0===s?$.distance:s,h=t.ignoreLocation,l=void 0===h?$.ignoreLocation:h,f=r/e.length;if(l)return f;var d=Math.abs(a-o);return u?f+d/u:d?1:f}var W=32;function T(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?$.location:i,c=r.distance,a=void 0===c?$.distance:c,s=r.threshold,u=void 0===s?$.threshold:s,h=r.findAllMatches,l=void 0===h?$.findAllMatches:h,f=r.minMatchCharLength,d=void 0===f?$.minMatchCharLength:f,v=r.includeMatches,g=void 0===v?$.includeMatches:v,y=r.ignoreLocation,p=void 0===y?$.ignoreLocation:y;if(t.length>W)throw new Error("Pattern length exceeds max of ".concat(W,"."));for(var m,k=t.length,M=e.length,b=Math.max(0,Math.min(o,M)),x=u,w=b,S=d>1||g,L=S?Array(M):[];(m=e.indexOf(t,w))>-1;){var _=N(t,{currentLocation:m,expectedLocation:b,distance:a,ignoreLocation:p});if(x=Math.min(_,x),w=m+k,S)for(var O=0;O=P;D-=1){var K=D-1,q=n[e.charAt(K)];if(S&&(L[K]=+!!q),z[D]=(z[D+1]<<1|1)&q,E&&(z[D]|=(j[D+1]|j[D])<<1|1|j[D+1]),z[D]&C&&(A=N(t,{errors:E,currentLocation:K,expectedLocation:b,distance:a,ignoreLocation:p}))<=x){if(x=A,(w=K)<=b)break;P=Math.max(1,2*b-w)}}if(N(t,{errors:E+1,currentLocation:b,expectedLocation:b,distance:a,ignoreLocation:p})>x)break;j=z}var B={isMatch:w>=0,score:Math.max(.001,A)};if(S){var J=function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:$.minMatchCharLength,n=[],r=-1,i=-1,o=0,c=e.length;o=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}(L,d);J.length?g&&(B.indices=J):B.isMatch=!1}return B}function z(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,c=void 0===o?$.location:o,a=i.threshold,s=void 0===a?$.threshold:a,u=i.distance,h=void 0===u?$.distance:u,l=i.includeMatches,f=void 0===l?$.includeMatches:l,d=i.findAllMatches,v=void 0===d?$.findAllMatches:d,g=i.minMatchCharLength,y=void 0===g?$.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?$.isCaseSensitive:p,k=i.ignoreLocation,M=void 0===k?$.ignoreLocation:k;if(r(this,e),this.options={location:c,threshold:s,distance:h,includeMatches:f,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:M},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var b=function(e,t){n.chunks.push({pattern:e,alphabet:z(e),startIndex:t})},x=this.pattern.length;if(x>W){for(var w=0,S=x%W,L=x-S;w1&&void 0!==arguments[1]?arguments[1]:{},c=o.location,a=void 0===c?$.location:c,s=o.threshold,u=void 0===s?$.threshold:s,h=o.distance,l=void 0===h?$.distance:h,f=o.includeMatches,d=void 0===f?$.includeMatches:f,v=o.findAllMatches,g=void 0===v?$.findAllMatches:v,y=o.minMatchCharLength,p=void 0===y?$.minMatchCharLength:y,m=o.isCaseSensitive,k=void 0===m?$.isCaseSensitive:m,M=o.ignoreLocation,b=void 0===M?$.ignoreLocation:M;return r(this,n),(i=t.call(this,e))._bitapSearch=new D(e,{location:a,threshold:u,distance:l,includeMatches:d,findAllMatches:g,minMatchCharLength:p,isCaseSensitive:k,ignoreLocation:b}),i}return o(n,[{key:"search",value:function(e){return this._bitapSearch.searchIn(e)}}],[{key:"type",get:function(){return"fuzzy"}},{key:"multiRegex",get:function(){return/^"(.*)"$/}},{key:"singleRegex",get:function(){return/^(.*)$/}}]),n}(K),X=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){for(var t,n=0,r=[],i=this.pattern.length;(t=e.indexOf(this.pattern,n))>-1;)n=t+i,r.push([t,n-1]);var o=!!r.length;return{isMatch:o,score:o?0:1,indices:r}}}],[{key:"type",get:function(){return"include"}},{key:"multiRegex",get:function(){return/^'"(.*)"$/}},{key:"singleRegex",get:function(){return/^'(.*)$/}}]),n}(K),Y=[B,X,U,V,H,G,J,Q],Z=Y.length,ee=/ +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,te=new Set([Q.type,X.type]),ne=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=n.isCaseSensitive,o=void 0===i?$.isCaseSensitive:i,c=n.includeMatches,a=void 0===c?$.includeMatches:c,s=n.minMatchCharLength,u=void 0===s?$.minMatchCharLength:s,h=n.ignoreLocation,l=void 0===h?$.ignoreLocation:h,f=n.findAllMatches,d=void 0===f?$.findAllMatches:f,v=n.location,g=void 0===v?$.location:v,y=n.threshold,p=void 0===y?$.threshold:y,m=n.distance,k=void 0===m?$.distance:m;r(this,e),this.query=null,this.options={isCaseSensitive:o,includeMatches:a,minMatchCharLength:u,findAllMatches:d,ignoreLocation:l,location:g,threshold:p,distance:k},this.pattern=o?t:t.toLowerCase(),this.query=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.split("|").map((function(e){for(var n=e.trim().split(ee).filter((function(e){return e&&!!e.trim()})),r=[],i=0,o=n.length;i2&&void 0!==arguments[2]?arguments[2]:{}).auto,r=void 0===n||n;return ue(e)||(e=he(e)),function e(n){var i=Object.keys(n),o=function(e){return!!e[ae]}(n);if(!o&&i.length>1&&!ue(n))return e(he(n));if(function(e){return!g(e)&&b(e)&&!ue(e)}(n)){var c=o?n[ae]:i[0],a=o?n[se]:n[c];if(!m(a))throw new Error(function(e){return"Invalid value for key ".concat(e)}(c));var s={keyId:C(c),pattern:a};return r&&(s.searcher=ie(a,t)),s}var u={children:[],operator:i[0]};return i.forEach((function(t){var r=n[t];g(r)&&r.forEach((function(t){u.children.push(e(t))}))})),u}(e)}function fe(e,t){var n=e.matches;t.matches=[],x(n)&&n.forEach((function(e){if(x(e.indices)&&e.indices.length){var n={indices:e.indices,value:e.value};e.key&&(n.key=e.key.src),e.idx>-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function de(e,t){t.score=e.score}var ve=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;r(this,e),this.options=t(t({},$),i),this.options.useExtendedSearch,this._keyStore=new j(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof R))throw new Error("Incorrect 'index' type");this._myIndex=t||P(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){x(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{}).limit,n=void 0===t?-1:t,r=this.options,i=r.includeMatches,o=r.includeScore,c=r.shouldSort,a=r.sortFn,s=r.ignoreFieldNorm,u=m(e)?m(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return function(e,t){var n=t.ignoreFieldNorm,r=void 0===n?$.ignoreFieldNorm:n;e.forEach((function(e){var t=1;e.matches.forEach((function(e){var n=e.key,i=e.norm,o=e.score,c=n?n.weight:null;t*=Math.pow(0===o&&c?Number.EPSILON:o,(c||1)*(r?1:i))})),e.score=t}))}(u,{ignoreFieldNorm:s}),c&&u.sort(a),k(n)&&n>-1&&(u=u.slice(0,n)),function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?$.includeMatches:r,o=n.includeScore,c=void 0===o?$.includeScore:o,a=[];return i&&a.push(fe),c&&a.push(de),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return a.length&&a.forEach((function(t){t(e,r)})),r}))}(u,this._docs,{includeMatches:i,includeScore:o})}},{key:"_searchStringList",value:function(e){var t=ie(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(x(n)){var c=t.searchIn(n),a=c.isMatch,s=c.score,u=c.indices;a&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:u}]})}})),r}},{key:"_searchLogical",value:function(e){var t=this,n=le(e,this.options),r=function e(n,r,i){if(!n.children){var o=n.keyId,c=n.searcher,a=t._findMatches({key:t._keyStore.get(o),value:t._myIndex.getValueForItemAtKeyId(r,o),searcher:c});return a&&a.length?[{idx:i,item:r,matches:a}]:[]}for(var s=[],u=0,h=n.children.length;u1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?$.getFn:n,i=t.fieldNormWeight,o=void 0===i?$.fieldNormWeight:i,c=e.keys,a=e.records,s=new R({getFn:r,fieldNormWeight:o});return s.setKeys(c),s.setIndexRecords(a),s},ve.config=$,function(){re.push.apply(re,arguments)}(ne),ve},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); \ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 4ddb3776..00000000 --- a/docs/index.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - Index - Chomp documentation - - - - - - - - - - - - - - - - diff --git a/docs/page.css b/docs/page.css deleted file mode 100644 index 1e054bd1..00000000 --- a/docs/page.css +++ /dev/null @@ -1 +0,0 @@ -*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{color:inherit;border-top-width:1px;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.mb-6{margin-bottom:1.5rem}.block{display:block}.flex{display:flex}.flex-1{flex:1}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-4{gap:1rem}.overflow-hidden{overflow:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.bg-transparent{background-color:#0000}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.italic{font-style:italic}.leading-none{line-height:1}.text-stone-400{--tw-text-opacity:1;color:rgb(168 162 158/var(--tw-text-opacity))}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}body{width:100%;max-width:1280px;margin-left:auto;margin-right:auto;padding:1.75rem;overflow-x:hidden}#content{gap:1.5rem;display:flex;position:relative}#content>main{flex:1}.toc{box-sizing:border-box;flex:none;width:16rem;max-height:100vh;position:sticky;top:0}@media not all and (min-width:1024px){.toc{display:none}}.toc>div{max-height:100%;overflow-y:scroll}.toc>div>:last-child{padding-bottom:1rem}#searchResults{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));display:none;position:absolute;inset:0}.hover\:bg-stone-100:hover{--tw-bg-opacity:1;background-color:rgb(245 245 244/var(--tw-bg-opacity))}@media not all and (min-width:1024px){.max-lg\:flex-col-reverse{flex-direction:column-reverse}}@media (min-width:1024px){.lg\:max-w-80{max-width:20rem}.lg\:items-center{align-items:center}} \ No newline at end of file diff --git a/docs/script.js b/docs/script.js deleted file mode 100644 index 15032006..00000000 --- a/docs/script.js +++ /dev/null @@ -1,33 +0,0 @@ -function findParent(el, find) { - do { - if (find(el)) { - return el; - } - } while (el = el.parentElement); -} - -document.addEventListener("click", (e) => { - const target = findParent( - e.target, - (el) => el instanceof HTMLButtonElement && el.dataset["copy"], - ); - if (target) { - navigator?.clipboard?.writeText(target.dataset["copy"]); - } -}); - -window.addEventListener("load", () => { - const usageSelector = document.getElementById("usageSelector"); - - document.addEventListener("mouseup", (e) => { - if ( - findParent( - e.target, - (el) => - el.parentElement === usageSelector && el instanceof HTMLDivElement, - ) - ) { - usageSelector.open = false; - } - }); -}); diff --git a/docs/search.js b/docs/search.js deleted file mode 100644 index c1495058..00000000 --- a/docs/search.js +++ /dev/null @@ -1,168 +0,0 @@ -const Fuse = window.Fuse; - -const searchInput = document.querySelector("#searchbar"); -const mainContentTags = document.getElementsByTagName("main"); -const searchResultsDiv = document.querySelector("#searchResults"); -const currentFile = - document.querySelector("meta[name='doc-current-file']").attributes - .getNamedItem("content").value; -const pathToRoot = "../".repeat( - currentFile ? (currentFile.split("/").length + 1) : 0, -); -searchInput.removeAttribute("style"); - -const SEARCH_INDEX = window.DENO_DOC_SEARCH_INDEX; - -const fuse = new Fuse(SEARCH_INDEX.nodes, { - keys: [{ - name: "name", - weight: 2, - }], - isCaseSensitive: false, - minMatchCharLength: 2, - threshold: 0.4, -}); - -const loadedUrl = new URL(window.location.href); -const val = loadedUrl.searchParams.get("q"); -if (val) { - searchInput.value = val; - doSearch(val); -} - -window.addEventListener("load", function () { - document.addEventListener("keydown", function (event) { - if (event.key.toLowerCase() === "s") { - if (event.target !== searchInput) { - searchInput.focus(); - event.preventDefault(); - } - } - }); - - const emptyPlaceholder = "Click or press 'S' to search..."; - searchInput.placeholder = emptyPlaceholder; - - searchInput.addEventListener("focus", function () { - searchInput.placeholder = "Type your query here..."; - }); - - searchInput.addEventListener("blur", function () { - searchInput.placeholder = emptyPlaceholder; - }); -}); - -function debounce(func, delay) { - let timerId; - - return function () { - const context = this; - const args = arguments; - - clearTimeout(timerId); - - timerId = setTimeout(function () { - func.apply(context, args); - }, delay); - }; -} - -const debouncedSearch = debounce(doSearch, 250); - -searchInput.addEventListener("input", (e) => { - const val = e.target.value; - debouncedSearch(val); -}); - -function doSearch(val) { - if (!val) { - updateCurrentLocation(val); - showPage(); - } else { - const results = searchInIndex(val); - // console.log("results", results); - updateCurrentLocation(val); - renderResults(results); - showSearchResults(); - } -} - -function updateCurrentLocation(val) { - const url = new URL(window.location.href); - if (val) { - url.searchParams.set("q", val); - } else { - url.searchParams.delete("q"); - } - window.history.replaceState({}, "", url.href); -} - -function showPage() { - for (const mainTag of mainContentTags) { - mainTag.style.display = "block"; - } - searchResultsDiv.style.display = "none"; -} - -function showSearchResults() { - for (const mainTag of mainContentTags) { - mainTag.style.display = "none"; - } - searchResultsDiv.style.display = "block"; -} - -function renderResults(results) { - if (results.length === 0) { - searchResultsDiv.innerHTML = `No result`; - return; - } - - let html = ``; - searchResultsDiv.innerHTML = html; -} - -function searchInIndex(val) { - return fuse.search(val).map((result) => result.item); -} - -function docNodeKindToStringVariants(kind) { - switch (kind) { - case "function": - return ["Function", "Function", "f"]; - case "variable": - return ["Variable", "Variable", "v"]; - case "class": - return ["Class", "Class", "c"]; - case "enum": - return ["Enum", "Enum", "E"]; - case "interface": - return ["Interface", "Interface", "I"]; - case "typeAlias": - return ["TypeAlias", "Type Alias", "T"]; - case "namespace": - return ["Namespace", "Namespace", "N"]; - default: - return []; - } -} diff --git a/docs/search_index.js b/docs/search_index.js deleted file mode 100644 index 87e79a01..00000000 --- a/docs/search_index.js +++ /dev/null @@ -1,3 +0,0 @@ -(function () { - window.DENO_DOC_SEARCH_INDEX = {"nodes":[{"kind":["enum"],"name":"Algorithms","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":229},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Authenticator","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":95},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Cache","file":".","location":{"filename":"","line":10,"col":0,"byteIndex":211},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"CheckSource","file":".","location":{"filename":"","line":38,"col":0,"byteIndex":1093},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Configure","file":".","location":{"filename":"","line":9,"col":0,"byteIndex":227},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Controller","file":".","location":{"filename":"","line":15,"col":0,"byteIndex":574},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"CouchDB","file":".","location":{"filename":"","line":21,"col":0,"byteIndex":355},"declarationKind":"export","deprecated":false},{"kind":["function","namespace"],"name":"Cron","file":".","location":{"filename":"","line":56,"col":0,"byteIndex":2427},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"Cron.Cron","file":".","location":{"filename":"","line":325,"col":5,"byteIndex":9058},"declarationKind":"declare","deprecated":false},{"kind":["variable"],"name":"DEFAULT_OPTS","file":".","location":{"filename":"","line":52,"col":13,"byteIndex":1435},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Druid","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["enum"],"name":"ErrorCodes","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Events","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":102},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"ExclusionConfig","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":94},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"File","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Folder","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":47},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"GraphQL","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Hash","file":".","location":{"filename":"","line":50,"col":0,"byteIndex":1339},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"INSECURE_ALGORITHMS","file":".","location":{"filename":"","line":41,"col":13,"byteIndex":1177},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Inflector","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":63},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"InfluxDB","file":".","location":{"filename":"","line":16,"col":0,"byteIndex":184},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Logger","file":".","location":{"filename":"","line":44,"col":0,"byteIndex":1500},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Loki","file":".","location":{"filename":"","line":9,"col":0,"byteIndex":179},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Ntfy","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":48},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Nut","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":152},"declarationKind":"export","deprecated":false},{"kind":["variable"],"name":"PASSWORD_DEFAULT","file":".","location":{"filename":"","line":8,"col":13,"byteIndex":247},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Password","file":".","location":{"filename":"","line":67,"col":0,"byteIndex":1718},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"PasswordOptions","file":".","location":{"filename":"","line":60,"col":0,"byteIndex":1549},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"QueryParameters","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":118},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Queue","file":".","location":{"filename":"","line":20,"col":0,"byteIndex":333},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"RCON","file":".","location":{"filename":"","line":8,"col":0,"byteIndex":132},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Random","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Redis","file":".","location":{"filename":"","line":4,"col":0,"byteIndex":148},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Request","file":".","location":{"filename":"","line":11,"col":0,"byteIndex":186},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"RequestParameters","file":".","location":{"filename":"","line":3,"col":0,"byteIndex":48},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Router","file":".","location":{"filename":"","line":20,"col":0,"byteIndex":762},"declarationKind":"export","deprecated":false},{"kind":["enum"],"name":"StatusCodes","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Text","file":".","location":{"filename":"","line":1,"col":0,"byteIndex":0},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Time","file":".","location":{"filename":"","line":5,"col":0,"byteIndex":242},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"TimeString","file":".","location":{"filename":"","line":84,"col":0,"byteIndex":1726},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"TimeStringSeconds","file":".","location":{"filename":"","line":111,"col":0,"byteIndex":2499},"declarationKind":"export","deprecated":false},{"kind":["interface"],"name":"ViewVariable","file":".","location":{"filename":"","line":11,"col":0,"byteIndex":499},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Webserver","file":".","location":{"filename":"","line":5,"col":0,"byteIndex":145},"declarationKind":"export","deprecated":false},{"kind":["class"],"name":"Websocket","file":".","location":{"filename":"","line":7,"col":0,"byteIndex":289},"declarationKind":"export","deprecated":false},{"kind":["function"],"name":"raise","file":".","location":{"filename":"","line":38,"col":0,"byteIndex":927},"declarationKind":"export","deprecated":false}]}; -})() \ No newline at end of file diff --git a/docs/styles.css b/docs/styles.css deleted file mode 100644 index ff3c7e07..00000000 --- a/docs/styles.css +++ /dev/null @@ -1 +0,0 @@ -.ddoc .container{width:100%}@media (min-width:640px){.ddoc .container{max-width:640px}}@media (min-width:768px){.ddoc .container{max-width:768px}}@media (min-width:1024px){.ddoc .container{max-width:1024px}}@media (min-width:1280px){.ddoc .container{max-width:1280px}}@media (min-width:1536px){.ddoc .container{max-width:1536px}}.ddoc .static{position:static}.ddoc .relative{position:relative}.ddoc .\!mb-0{margin-bottom:0!important}.ddoc .\!ml-2{margin-left:.5rem!important}.ddoc .ml-2{margin-left:.5rem}.ddoc .ml-4{margin-left:1rem}.ddoc .mr-2{margin-right:.5rem}.ddoc .mt-3{margin-top:.75rem}.ddoc .block{display:block}.ddoc .inline{display:inline}.ddoc .flex{display:flex}.ddoc .inline-flex{display:inline-flex}.ddoc .table{display:table}.ddoc .contents{display:contents}.ddoc .hidden{display:none}.ddoc .h-4{height:1rem}.ddoc .h-5{height:1.25rem}.ddoc .min-w-0{min-width:0}.ddoc .flex-1{flex:1}.ddoc .flex-none{flex:none}.ddoc .grow{flex-grow:1}.ddoc .rotate-90{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.ddoc .items-center{align-items:center}.ddoc .gap-0{gap:0}.ddoc .gap-0\.5{gap:.125rem}.ddoc .gap-1{gap:.25rem}.ddoc .gap-2{gap:.5rem}.ddoc .space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*calc(1 - var(--tw-space-x-reverse)))}.ddoc .space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*calc(1 - var(--tw-space-x-reverse)))}.ddoc .space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.ddoc .space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.ddoc .space-y-7>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.75rem*var(--tw-space-y-reverse))}.ddoc .overflow-x-auto{overflow-x:auto}.ddoc .break-words{overflow-wrap:break-word}.ddoc .break-all{word-break:break-all}.ddoc .rounded-full{border-radius:9999px}.ddoc .border{border-width:1px}.ddoc .border-l-2{border-left-width:2px}.ddoc .border-stone-300{--tw-border-opacity:1;border-color:rgb(214 211 209/var(--tw-border-opacity))}.ddoc .bg-Class\/15{background-color:#20b44b26}.ddoc .bg-Enum\/15{background-color:#22abb026}.ddoc .bg-Function\/15{background-color:#056cf026}.ddoc .bg-Interface\/15{background-color:#d2a06426}.ddoc .bg-Method\/15{background-color:#056cf026}.ddoc .bg-Namespace\/15{background-color:#d2564626}.ddoc .bg-Property\/15{background-color:#7e57c026}.ddoc .bg-TypeAlias\/15{background-color:#a4478c26}.ddoc .bg-Variable\/15{background-color:#7e57c026}.ddoc .bg-abstract\/15{background-color:#0cafc626}.ddoc .bg-deprecated\/15{background-color:#dc262626}.ddoc .bg-new\/15{background-color:#7b61ff26}.ddoc .bg-optional\/15{background-color:#0cafc626}.ddoc .bg-other\/15{background-color:#57534e26}.ddoc .bg-permissions\/15{background-color:#0cafc626}.ddoc .bg-private\/15,.ddoc .bg-protected\/15,.ddoc .bg-readonly\/15,.ddoc .bg-writeonly\/15{background-color:#7b61ff26}.ddoc .px-2{padding-left:.5rem;padding-right:.5rem}.ddoc .px-3{padding-left:.75rem;padding-right:.75rem}.ddoc .py-1{padding-top:.25rem;padding-bottom:.25rem}.ddoc .py-2{padding-top:.5rem;padding-bottom:.5rem}.ddoc .pl-4{padding-left:1rem}.ddoc .text-sm{font-size:.875rem;line-height:1.25rem}.ddoc .text-xl{font-size:1.25rem;line-height:1.75rem}.ddoc .font-bold{font-weight:700}.ddoc .font-medium{font-weight:500}.ddoc .font-normal{font-weight:400}.ddoc .italic{font-style:italic}.ddoc .leading-none{line-height:1}.ddoc .text-Class{--tw-text-opacity:1;color:rgb(32 180 75/var(--tw-text-opacity))}.ddoc .text-Enum{--tw-text-opacity:1;color:rgb(34 171 176/var(--tw-text-opacity))}.ddoc .text-Function{--tw-text-opacity:1;color:rgb(5 108 240/var(--tw-text-opacity))}.ddoc .text-Interface{--tw-text-opacity:1;color:rgb(210 160 100/var(--tw-text-opacity))}.ddoc .text-Method{--tw-text-opacity:1;color:rgb(5 108 240/var(--tw-text-opacity))}.ddoc .text-Namespace{--tw-text-opacity:1;color:rgb(210 86 70/var(--tw-text-opacity))}.ddoc .text-Property{--tw-text-opacity:1;color:rgb(126 87 192/var(--tw-text-opacity))}.ddoc .text-TypeAlias{--tw-text-opacity:1;color:rgb(164 71 140/var(--tw-text-opacity))}.ddoc .text-Variable{--tw-text-opacity:1;color:rgb(126 87 192/var(--tw-text-opacity))}.ddoc .text-\[\#0F172A\]{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity))}.ddoc .text-abstract{--tw-text-opacity:1;color:rgb(12 175 198/var(--tw-text-opacity))}.ddoc .text-deprecated{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity))}.ddoc .text-new{--tw-text-opacity:1;color:rgb(123 97 255/var(--tw-text-opacity))}.ddoc .text-optional{--tw-text-opacity:1;color:rgb(12 175 198/var(--tw-text-opacity))}.ddoc .text-other{--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity))}.ddoc .text-permissions{--tw-text-opacity:1;color:rgb(12 175 198/var(--tw-text-opacity))}.ddoc .text-private,.ddoc .text-protected,.ddoc .text-readonly,.ddoc .text-writeonly{--tw-text-opacity:1;color:rgb(123 97 255/var(--tw-text-opacity))}.ddoc summary::-webkit-details-marker{display:none}.ddoc{--ddoc-selection-border-width:2px;--ddoc-selection-border-color-default:#d6d3d1;--ddoc-selection-selected-border-color:#2564eb;--ddoc-selection-selected-bg:#056cf00c;--ddoc-selection-padding:9px 15px}.ddoc .link{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:75ms;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ddoc .link:hover{--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity))}.ddoc .anchor{float:left;--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity));margin-left:-24px;padding:.25rem;line-height:1;display:none;top:0;bottom:0}.ddoc .anchorable{position:relative}.ddoc .anchorable:hover .anchor{display:block}.ddoc .deprecated>div:first-child{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity));align-items:center;gap:.25rem;padding-top:.25rem;padding-bottom:.25rem;display:flex}.ddoc .deprecated>div:first-child>span{font-weight:600;line-height:1.5rem}.ddoc .deprecated>div:nth-child(2){--tw-border-opacity:1;border-left-width:4px;border-color:rgb(252 165 165/var(--tw-border-opacity));margin-left:.25rem;padding-left:.5rem}.ddoc .symbolSubtitle>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.125rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem*var(--tw-space-y-reverse))}.ddoc .symbolSubtitle{font-size:.875rem;line-height:1rem}.ddoc .symbolSubtitle .type{--tw-text-opacity:1;color:rgb(168 162 158/var(--tw-text-opacity));font-style:italic}.ddoc .docEntry{font-size:.875rem;line-height:1.25rem}.ddoc .docEntry .docEntryHeader{justify-content:space-between;align-items:flex-start;display:flex}.ddoc .docEntry .docEntryHeader>span{overflow-wrap:break-word;align-items:center;gap:.5rem;display:flex}.ddoc .section>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.ddoc .section>div>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.ddoc .section>div>h2{padding-top:.25rem;padding-bottom:.25rem;font-size:1.25rem;font-weight:600;line-height:1.5rem}.ddoc .namespaceSection{grid-template-columns:repeat(1,minmax(0,1fr));row-gap:.75rem;display:grid}@media (min-width:768px){.ddoc .namespaceSection{-moz-column-gap:2rem;grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem}}@media (min-width:1024px){.ddoc .namespaceSection{grid-template-columns:repeat(3,minmax(0,1fr))}}.ddoc .namespaceSection .namespaceItem{-moz-column-gap:.625rem;column-gap:.625rem;display:flex}.ddoc .namespaceSection .namespaceItem .docNodeKindIcon{flex-direction:column;justify-content:flex-start;width:auto}.ddoc .namespaceSection .namespaceItem .docNodeKindIcon>*+*{margin-top:-.125rem;margin-left:0}.ddoc .namespaceSection .namespaceItem[aria-label=deprecated]{opacity:.6}.ddoc .namespaceSection .namespaceItem[aria-label=deprecated] .namespaceItemContent>a{--tw-text-opacity:1;color:rgb(120 113 108/var(--tw-text-opacity));text-decoration-line:line-through;text-decoration-color:#78716cb3;text-decoration-thickness:2px}.ddoc .namespaceSection .namespaceItem .namespaceItemContent>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.375rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem*var(--tw-space-y-reverse))}.ddoc .namespaceSection .namespaceItem .namespaceItemContent>a{word-break:break-all;font-weight:500;line-height:1.25;display:block}.ddoc .namespaceSection .namespaceItem .namespaceItemContent>div{--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity));font-size:.875rem;line-height:1.25rem}.ddoc .symbolGroup>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(3rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(3rem*var(--tw-space-y-reverse))}.ddoc .symbolGroup article>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem*var(--tw-space-y-reverse))}.ddoc .symbolGroup article>div:first-child{justify-content:space-between;align-items:flex-start;display:flex}.ddoc .symbolGroup article>div:first-child>div:first-child>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.ddoc .symbolGroup article>div:first-child>div:first-child{font-weight:500}.ddoc .docNodeKindIcon{flex-shrink:0;justify-content:flex-end;display:inline-flex}.ddoc .docNodeKindIcon div{-webkit-user-select:none;user-select:none;text-align:center;vertical-align:middle;border-radius:9999px;flex-shrink:0;width:1.25rem;height:1.25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.75rem;font-weight:500;line-height:1.25rem}.ddoc .docNodeKindIcon>*+*{margin-left:-.375rem}.ddoc .example details summary{cursor:pointer;border-radius:.5rem;align-items:center;gap:.5rem;width:100%;padding-top:.5rem;padding-bottom:.5rem;line-height:1.5rem;list-style-type:none;display:flex}.ddoc .example details summary>div:first-child{-webkit-user-select:none;user-select:none;--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity))}.ddoc .example details[open] summary>div:first-child{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.ddoc .toc h3{margin-bottom:.75rem;font-size:1.125rem;font-weight:700;line-height:1.75rem}.ddoc .toc>div>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem*var(--tw-space-y-reverse))}.ddoc .toc .topSymbols>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.ddoc .toc .topSymbols{font-size:.875rem;line-height:1.25rem}.ddoc .toc .topSymbols ul{list-style-type:none}.ddoc .toc .topSymbols ul>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.625rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem*var(--tw-space-y-reverse))}.ddoc .toc .topSymbols ul li{display:block}.ddoc .toc .topSymbols ul li a{align-items:center;gap:.5rem;display:flex}.ddoc .toc .topSymbols ul li a>span{text-overflow:ellipsis;white-space:nowrap;border-radius:.25rem;width:100%;margin-top:-.125rem;margin-bottom:-.125rem;margin-left:-.25rem;padding-top:.125rem;padding-bottom:.125rem;padding-left:.25rem;display:block;overflow:hidden}.ddoc .toc .topSymbols>a:hover{text-decoration-line:underline}.ddoc .toc .documentNavigation>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.ddoc .toc .documentNavigation{font-size:.875rem;line-height:1.25rem}.ddoc .toc .documentNavigation>ul{display:block}.ddoc .toc .documentNavigation>ul>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.ddoc .toc .documentNavigation>ul{overflow-y:auto}.ddoc .toc .documentNavigation>ul ul{margin-left:.875rem}.ddoc .toc .documentNavigation>ul ul>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.ddoc .toc .documentNavigation a{text-overflow:ellipsis;white-space:nowrap;display:block;overflow-x:hidden}.ddoc .toc .documentNavigation a:hover{text-decoration-line:underline}.ddoc .usages nav{flex-direction:row;align-items:center;gap:.5rem;margin-bottom:.75rem;font-weight:600;display:flex}.ddoc .usages nav details>summary{cursor:pointer;-webkit-user-select:none;user-select:none;--tw-border-opacity:1;border-width:1px;border-color:rgb(209 213 219/var(--tw-border-opacity));border-radius:.25rem;gap:.25rem;padding:.5rem .75rem;display:flex}@media (min-width:768px){.ddoc .usages nav details>div{position:relative}}.ddoc .usages nav details>div>div{z-index:30;--tw-border-opacity:1;border-width:1px;border-color:rgb(209 213 219/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));margin-top:.375rem;padding:.5rem;display:block;position:absolute}@media not all and (min-width:768px){.ddoc .usages nav details>div>div{border-left-width:0;border-right-width:0;left:0;right:0}}@media (min-width:768px){.ddoc .usages nav details>div>div{border-radius:.25rem;width:12rem}}.ddoc .usages nav details>div>div label{cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:.125rem;align-items:center;gap:.5rem;padding:.25rem .5rem;line-height:1.5;display:flex}.ddoc .usages nav details>div>div label:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.ddoc .usageContent .markdown{--tw-text-opacity:1;color:rgb(104 104 104/var(--tw-text-opacity));font-size:.75rem;line-height:1rem}.ddoc .usageContent .markdown p{margin:0}.ddoc .usageContent pre.highlight{--tw-border-opacity:1;border-width:1px;border-color:rgb(209 213 219/var(--tw-border-opacity));background-color:#0000}@media not all and (min-width:768px){.ddoc .usageContent pre.highlight{border-left-width:0;border-right-width:0}}.ddoc .usageContent pre.highlight{margin-top:.25rem!important}.ddoc .usageContent pre.highlight>code:first-child{scrollbar-width:thin;padding:.5rem .75rem}.ddoc .usageContent pre.highlight .context_button{border-width:0;display:none;top:.25rem;right:.5rem}.ddoc .usageContent pre.highlight .context_button svg rect{fill:#fff}.ddoc .usageContent pre.highlight:hover .context_button{opacity:1;display:block}.ddoc .contextLink{color:#0e6590cc;text-underline-offset:4px;text-decoration-line:underline;text-decoration-color:#0e659080;text-decoration-thickness:1.5px}.ddoc .contextLink:hover{--tw-text-opacity:1;color:rgb(14 101 144/var(--tw-text-opacity));text-decoration-color:#0e6590}.ddoc .breadcrumbs{word-break:break-all;align-items:center;gap:.25rem;display:inline-flex}.ddoc .breadcrumbs>li:first-child{font-size:1.25rem;font-weight:700;line-height:1}@media (min-width:1024px){.ddoc .breadcrumbs>li:first-child{font-size:1.5rem;line-height:2rem}}.ddoc .breadcrumbs li{line-height:.9em;display:inline}@media (min-width:1024px){.ddoc .breadcrumbs li{font-size:1.25rem;line-height:1.75rem}}.ddoc .functionOverload{cursor:pointer;display:block}.ddoc .functionOverload>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.ddoc .functionOverload{--tw-border-opacity:1;border-width:1px;border-color:rgb(214 211 209/var(--tw-border-opacity));border-radius:.5rem;padding:.625rem 1rem}.ddoc .functionOverload:hover{--tw-bg-opacity:1;background-color:rgb(245 245 244/var(--tw-bg-opacity))}.ddoc .context_button{z-index:10;cursor:pointer;background-color:inherit;border-width:1px;border-radius:.25rem;padding:.375rem;line-height:0}.ddoc .context_button:hover{--tw-bg-opacity:1;background-color:rgb(231 229 228/var(--tw-bg-opacity))}.ddoc .markdown_border{border-color:#d6d3d166;border-left-width:2px;margin-left:.25rem;padding-left:.625rem}.ddoc .markdown_summary{--tw-text-opacity:1;color:rgb(87 83 78/var(--tw-text-opacity));display:inline}.ddoc .markdown_summary p{display:inline-block}.ddoc .markdown_summary :not(pre)>code{--tw-bg-opacity:1;background-color:rgb(231 229 228/var(--tw-bg-opacity));border-radius:.25rem;padding:.125rem .25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem}.ddoc .markdown{flex-shrink:1;min-width:0}.ddoc .markdown>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.ddoc .markdown a:not(.no_color){--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:75ms;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ddoc .markdown a:not(.no_color):hover{--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity))}.ddoc .markdown h1{--tw-border-opacity:1;border-bottom-width:1px;border-color:rgb(214 211 209/var(--tw-border-opacity));padding-bottom:.25rem;font-size:1.25rem;line-height:1.75rem}@media (min-width:768px){.ddoc .markdown h1{font-size:1.5rem;line-height:2rem}}@media (min-width:1024px){.ddoc .markdown h1{font-size:1.875rem;line-height:2.25rem}}.ddoc .markdown h2{--tw-border-opacity:1;border-bottom-width:1px;border-color:rgb(214 211 209/var(--tw-border-opacity));padding-bottom:.25rem;font-size:1.125rem;line-height:1.75rem}@media (min-width:768px){.ddoc .markdown h2{font-size:1.25rem;line-height:1.75rem}}@media (min-width:1024px){.ddoc .markdown h2{font-size:1.5rem;line-height:2rem}}.ddoc .markdown h3{font-weight:700}@media (min-width:768px){.ddoc .markdown h3{font-size:1.125rem;font-weight:400;line-height:1.75rem}}@media (min-width:1024px){.ddoc .markdown h3{font-size:1.25rem;font-weight:400;line-height:1.75rem}}.ddoc .markdown h4{font-weight:600}@media (min-width:768px){.ddoc .markdown h4{font-weight:700}}@media (min-width:1024px){.ddoc .markdown h4{font-size:1.125rem;font-weight:400;line-height:1.75rem}}.ddoc .markdown h5{font-style:italic}@media (min-width:768px){.ddoc .markdown h5{font-weight:600}}@media (min-width:1024px){.ddoc .markdown h5{font-weight:700}}@media (min-width:768px){.ddoc .markdown h6{font-style:italic}}@media (min-width:1024px){.ddoc .markdown h6{font-weight:600}}.ddoc .markdown hr{--tw-border-opacity:1;border-color:rgb(120 113 108/var(--tw-border-opacity));margin:.5rem}.ddoc .markdown ol,.ddoc .markdown ul{margin-left:1rem;list-style-position:outside}.ddoc .markdown ol{list-style-type:decimal}.ddoc .markdown ul{list-style-type:disc}.ddoc .markdown :not(pre)>code{--tw-bg-opacity:1;background-color:rgb(231 229 228/var(--tw-bg-opacity));border-radius:.25rem;padding:.125rem .25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem}:is(.ddoc .markdown h1,.ddoc .markdown h2,.ddoc .markdown h3,.ddoc .markdown h4,.ddoc .markdown h5,.ddoc .markdown h6)>code{font-size:inherit!important}.ddoc .markdown pre{--tw-bg-opacity:1;background-color:rgb(245 245 244/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity));border-radius:.5rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem}.ddoc .markdown pre>code:first-child{padding:1rem;display:block;overflow-x:auto}.ddoc .markdown p{margin:.25rem 0}.ddoc .markdown table{table-layout:auto;width:max-content;max-width:100%;display:block;overflow:auto}.ddoc .markdown td{--tw-border-opacity:1;border-width:1px;border-color:rgb(120 113 108/var(--tw-border-opacity));padding:.5rem}.ddoc .markdown th{text-align:center;font-weight:700}.ddoc .markdown img{display:inline-block}.ddoc .markdown .alert>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.ddoc .markdown .alert{border-left-width:4px;padding:.5rem 1rem}.ddoc .markdown .alert div:first-child{align-items:center;gap:.375rem;font-weight:500;display:flex}.ddoc .markdown .alert div:first-child svg{width:1.25rem;height:1.25rem}.ddoc .markdown .alert-note{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity))}.ddoc .markdown .alert-note div:first-child{stroke:#2563eb;--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.ddoc .markdown .alert-tip{--tw-border-opacity:1;border-color:rgb(22 163 74/var(--tw-border-opacity))}.ddoc .markdown .alert-tip div:first-child{stroke:#16a34a;--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity))}.ddoc .markdown .alert-important{--tw-border-opacity:1;border-color:rgb(147 51 234/var(--tw-border-opacity))}.ddoc .markdown .alert-important div:first-child{stroke:#9333ea;--tw-text-opacity:1;color:rgb(147 51 234/var(--tw-text-opacity))}.ddoc .markdown .alert-warning{--tw-border-opacity:1;border-color:rgb(202 138 4/var(--tw-border-opacity))}.ddoc .markdown .alert-warning div:first-child{stroke:#ca8a04;--tw-text-opacity:1;color:rgb(202 138 4/var(--tw-text-opacity))}.ddoc .markdown .alert-caution{--tw-border-opacity:1;border-color:rgb(220 38 38/var(--tw-border-opacity))}.ddoc .markdown .alert-caution div:first-child{stroke:#dc2626;--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity))}.ddoc .markdown .highlight{position:relative}.ddoc .markdown .highlight .lineNumbers{--tw-border-opacity:1;border-right-width:2px;border-color:rgb(214 211 209/var(--tw-border-opacity));text-align:right;flex:none;padding-right:.25rem}.ddoc .markdown .highlight .context_button{opacity:.6;position:absolute;top:.75rem;right:1rem}.ddoc .markdown .highlight .context_button:hover{opacity:1}.ddoc .markdown .highlight .pl-c{color:#6a737d}.ddoc .markdown .highlight .pl-c1,.ddoc .markdown .highlight .pl-s .pl-v{color:#005cc5}.ddoc .markdown .highlight .pl-e,.ddoc .markdown .highlight .pl-en{color:#6f42c1}.ddoc .markdown .highlight .pl-smi,.ddoc .markdown .highlight .pl-s .pl-s1{color:#24292e}.ddoc .markdown .highlight .pl-ent{color:#22863a}.ddoc .markdown .highlight .pl-k{color:#d73a49}.ddoc .markdown .highlight .pl-s,.ddoc .markdown .highlight .pl-pds,.ddoc .markdown .highlight .pl-s .pl-pse .pl-s1,.ddoc .markdown .highlight .pl-sr,.ddoc .markdown .highlight .pl-sr .pl-cce,.ddoc .markdown .highlight .pl-sr .pl-sre,.ddoc .markdown .highlight .pl-sr .pl-sra{color:#032f62}.ddoc .markdown .highlight .pl-v,.ddoc .markdown .highlight .pl-smw{color:#e36209}.ddoc .markdown .highlight .pl-bu{color:#b31d28}.ddoc .markdown .highlight .pl-ii{color:#fafbfc;background-color:#b31d28}.ddoc .markdown .highlight .pl-c2{color:#fafbfc;background-color:#d73a49}.ddoc .markdown .highlight .pl-c2:before{content:"^M"}.ddoc .markdown .highlight .pl-sr .pl-cce{color:#22863a;font-weight:700}.ddoc .markdown .highlight .pl-ml{color:#735c0f}.ddoc .markdown .highlight .pl-mh,.ddoc .markdown .highlight .pl-mh .pl-en,.ddoc .markdown .highlight .pl-ms{color:#005cc5;font-weight:700}.ddoc .markdown .highlight .pl-mi{color:#24292e;font-style:italic}.ddoc .markdown .highlight .pl-mb{color:#24292e;font-weight:700}.ddoc .markdown .highlight .pl-md{color:#b31d28;background-color:#ffeef0}.ddoc .markdown .highlight .pl-mi1{color:#22863a;background-color:#f0fff4}.ddoc .markdown .highlight .pl-mc{color:#e36209;background-color:#ffebda}.ddoc .markdown .highlight .pl-mi2{color:#f6f8fa;background-color:#005cc5}.ddoc .\*\:h-4>*{height:1rem}.ddoc .\*\:h-5>*{height:1.25rem}.ddoc .\*\:w-auto>*{width:auto}.ddoc .\*\:flex-none>*{flex:none}.ddoc .target\:bg-yellow-200:target{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.ddoc .hover\:bg-Class\/15:hover{background-color:#20b44b26}.ddoc .hover\:bg-Enum\/15:hover{background-color:#22abb026}.ddoc .hover\:bg-Function\/15:hover{background-color:#056cf026}.ddoc .hover\:bg-Interface\/15:hover{background-color:#d2a06426}.ddoc .hover\:bg-Method\/15:hover{background-color:#056cf026}.ddoc .hover\:bg-Namespace\/15:hover{background-color:#d2564626}.ddoc .hover\:bg-Property\/15:hover{background-color:#7e57c026}.ddoc .hover\:bg-TypeAlias\/15:hover{background-color:#a4478c26}.ddoc .hover\:bg-Variable\/15:hover{background-color:#7e57c026}.ddoc .hover\:bg-abstract\/15:hover{background-color:#0cafc626}.ddoc .hover\:bg-deprecated\/15:hover{background-color:#dc262626}.ddoc .hover\:bg-new\/15:hover{background-color:#7b61ff26}.ddoc .hover\:bg-optional\/15:hover{background-color:#0cafc626}.ddoc .hover\:bg-other\/15:hover{background-color:#57534e26}.ddoc .hover\:bg-permissions\/15:hover{background-color:#0cafc626}.ddoc .hover\:bg-private\/15:hover,.ddoc .hover\:bg-protected\/15:hover,.ddoc .hover\:bg-readonly\/15:hover,.ddoc .hover\:bg-writeonly\/15:hover{background-color:#7b61ff26} \ No newline at end of file diff --git a/docs/~/Algorithms.html b/docs/~/Algorithms.html deleted file mode 100644 index beefce58..00000000 --- a/docs/~/Algorithms.html +++ /dev/null @@ -1,1228 +0,0 @@ - - - - Algorithms - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- enum Algorithms -
- - - - -

List of algorithms supported by this library

-
-
- - - - - - - - - - -
- BLAKE2B = "BLAKE2B" - - - - - - -
-
- - - - - - - - - - -
- BLAKE2B256 = "BLAKE2B-256" - - - - - - -
-
- - - - - - - - - - -
- BLAKE2B384 = "BLAKE2B-384" - - - - - - -
-
- - - - - - - - - - -
- BLAKE2S = "BLAKE2S" - - - - - - -
-
- - - - - - - - - - -
- BLAKE3 = "BLAKE3" - - - - - - -
-
- - - - - - - - - - -
- KECCAK224 = "KECCAK-224" - - - - - - -
-
- - - - - - - - - - -
- KECCAK256 = "KECCAK-256" - - - - - - -
-
- - - - - - - - - - -
- KECCAK384 = "KECCAK-384" - - - - - - -
-
- - - - - - - - - - -
- KECCAK512 = "KECCAK-512" - - - - - - -
-
- - - - - - - - - - -
- MD5 = "MD5" - - - - - - -
-
- - - - - - - - - - -
- RIPEMD160 = "RIPEMD-160" - - - - - - -
-
- - - - - - - - - - -
- SHA1 = "SHA-1" - - - - - - -
-
- - - - - - - - - - -
- SHA224 = "SHA-224" - - - - - - -
-
- - - - - - - - - - -
- SHA256 = "SHA-256" - - - - - - -
-
- - - - - - - - - - -
- SHA384 = "SHA-384" - - - - - - -
-
- - - - - - - - - - -
- SHA3_224 = "SHA3-224" - - - - - - -
-
- - - - - - - - - - -
- SHA3_256 = "SHA3-256" - - - - - - -
-
- - - - - - - - - - -
- SHA3_384 = "SHA3-384" - - - - - - -
-
- - - - - - - - - - -
- SHA3_512 = "SHA3-512" - - - - - - -
-
- - - - - - - - - - -
- SHA512 = "SHA-512" - - - - - - -
-
- - - - - - - - - - -
- SHAKE128 = "SHAKE128" - - - - - - -
-
- - - - - - - - - - -
- SHAKE256 = "SHAKE256" - - - - - - -
-
-
-
-
-
-
-

Usage

import { Algorithms } from ".";
-
-
-
-
- - diff --git a/docs/~/Authenticator.client.html b/docs/~/Authenticator.client.html deleted file mode 100644 index e0f117f8..00000000 --- a/docs/~/Authenticator.client.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - Authenticator.client - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Authenticator.client -
- - - - -
-
- -

Check whether the passed token matches the "websocket_client_auth" key in the Configure

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
-
optional
-
token: string = - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Authenticator } from ".";
-
-
-
-
- - diff --git a/docs/~/Authenticator.html b/docs/~/Authenticator.html deleted file mode 100644 index 4b214a60..00000000 --- a/docs/~/Authenticator.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - Authenticator - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Authenticator } from ".";
-
-
-
-
- - diff --git a/docs/~/Authenticator.prototype.html b/docs/~/Authenticator.prototype.html deleted file mode 100644 index a8d916b2..00000000 --- a/docs/~/Authenticator.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Cache._items.html b/docs/~/Cache._items.html deleted file mode 100644 index 02def437..00000000 --- a/docs/~/Cache._items.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Cache._items - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/Cache.consume.html b/docs/~/Cache.consume.html deleted file mode 100644 index 7a27a919..00000000 --- a/docs/~/Cache.consume.html +++ /dev/null @@ -1,372 +0,0 @@ - - - - Cache.consume - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Cache.consume -
- - - - -
-
- -

Consume an item from the cache. -Differs from "Cache.get()" in that it removes the item afterwards.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
-
-const item = Cache.consume('cache item name');
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
optimistic: boolean = false - -
- - - - -

Whether to serve expired items from the cache

-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- unknown | null - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/Cache.dump.html b/docs/~/Cache.dump.html deleted file mode 100644 index d858377b..00000000 --- a/docs/~/Cache.dump.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - Cache.dump - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Cache.dump -
- - - - -
-
- -

Dumps the raw cache contents. -Should only be used for debugging purposes.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
-
-console.log(Cache.dump());
-
-
-
-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Map<string, CacheItem> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/Cache.exists.html b/docs/~/Cache.exists.html deleted file mode 100644 index e774f555..00000000 --- a/docs/~/Cache.exists.html +++ /dev/null @@ -1,319 +0,0 @@ - - - - Cache.exists - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Cache.exists -
- - - - -
-
- -

Check whether an item exists in the cache. -This does not check whether the item has expired or not.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
-
-const doesExist = Cache.exists('cache item name');
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/Cache.expired.html b/docs/~/Cache.expired.html deleted file mode 100644 index 447c1c0a..00000000 --- a/docs/~/Cache.expired.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - Cache.expired - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Cache.expired -
- - - - -
-
- -

Check whether an item has expired

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
-
-const hasExpired = Cache.expired('cache item name');
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/Cache.get.html b/docs/~/Cache.get.html deleted file mode 100644 index 076797a5..00000000 --- a/docs/~/Cache.get.html +++ /dev/null @@ -1,412 +0,0 @@ - - - - Cache.get - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Cache.get -
- - - - -
-
- -

Get an item from the cache

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
-
-Cache.get('cache item name');
-
-
-
-
-
- - - - - - - - - - -
- -

Getting expired items

-
-
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
-
-const item = Cache.get('cache item name', true);
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
optimistic: boolean = false - -
- - - - -

Whether to serve expired items from the cache

-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- unknown | null - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/Cache.html b/docs/~/Cache.html deleted file mode 100644 index 8dc96e44..00000000 --- a/docs/~/Cache.html +++ /dev/null @@ -1,602 +0,0 @@ - - - - Cache - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Cache -
- - - - -
-
-

- - - - - - - - - - -Static Properties

- - - - - - - - - - -
-
private
-
_items: Map<string, CacheItem> - -
- - - - -
-
-
-
-

- - - - - - - - - - -Static Methods

- - - - - - - - - - -
- consume(key: string, optimistic?: boolean): unknown | null - - - - - - -

Consume an item from the cache. -Differs from "Cache.get()" in that it removes the item afterwards.

-
-
- - - - - - - - - - -
- dump(): Map<string, CacheItem> - - - - - - -

Dumps the raw cache contents. -Should only be used for debugging purposes.

-
-
- - - - - - - - - - -
- exists(key: string): boolean - - - - - - -

Check whether an item exists in the cache. -This does not check whether the item has expired or not.

-
-
- - - - - - - - - - -
- expired(key: string): boolean - - - - - - -

Check whether an item has expired

-
-
- - - - - - - - - - -
- get(key: string, optimistic?: boolean): unknown | null - - - - - - -

Get an item from the cache

-
-
- - - - - - - - - - -
- remove(key: string): void - - - - - - -

Remove an item from the cache

-
-
- - - - - - - - - - -
- set(key: string, value: unknown, expiry?: string | null): void - - - - - - -

Add an item to the cache.

-
-
- - - - - - - - - - -
- sweep(): void - - - - - - -

Scan the cache and clean up expired items while keeping optimistic caching in tact. -There shouldn't be a need to manually run this in most cases.

-
-
-
-
-
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/Cache.prototype.html b/docs/~/Cache.prototype.html deleted file mode 100644 index 09ce7189..00000000 --- a/docs/~/Cache.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Cache.remove.html b/docs/~/Cache.remove.html deleted file mode 100644 index 6abff0e6..00000000 --- a/docs/~/Cache.remove.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - Cache.remove - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Cache.remove -
- - - - -
-
- -

Remove an item from the cache

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
-
-Cache.remove('cache item name');
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/Cache.set.html b/docs/~/Cache.set.html deleted file mode 100644 index ccb9cb92..00000000 --- a/docs/~/Cache.set.html +++ /dev/null @@ -1,427 +0,0 @@ - - - - Cache.set - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Cache.set -
- - - - -
-
- -

Add an item to the cache.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
-
-Cache.set('I expire in 1 minute', 'foo');
-Cache.set('I expire in 10 minutes', 'bar', '+10 minutes');
-Cache.set('I never expire', 'baz', null);
-
-

NOTE: Expiry times use TimeString formats.

-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
- - - - - - - - - - -
- value: unknown - - - - - - -
-
- - - - - - - - - - -
-
optional
-
expiry: string | null = +1 minute - -
- - - - -

Can be set to null for never expiring items

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/Cache.sweep.html b/docs/~/Cache.sweep.html deleted file mode 100644 index c8ab8c72..00000000 --- a/docs/~/Cache.sweep.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - Cache.sweep - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Cache.sweep -
- - - - -
-
- -

Scan the cache and clean up expired items while keeping optimistic caching in tact. -There shouldn't be a need to manually run this in most cases.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Cache } from "https://deno.land/x/chomp/core/cache.ts";
-
-Cache.sweep();
-
-
-
-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Cache } from ".";
-
-
-
-
- - diff --git a/docs/~/CheckSource.html b/docs/~/CheckSource.html deleted file mode 100644 index 2fad0287..00000000 --- a/docs/~/CheckSource.html +++ /dev/null @@ -1,679 +0,0 @@ - - - - CheckSource - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class CheckSource -
- - - - -

Check all files in the specified directories. -Doing this allows the program to start up significantly faster after deployment. -It is NOT a replacement for "deno lint".

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { CheckSource } from "https://deno.land/x/chomp/utility/check-source.ts";
-
-const checker = new CheckSource(['./src']);
-await checker.run();
-
-
-
-
-
- - - - - - - - - - -
- -

Exclude a directory

-
-
import { CheckSource } from "https://deno.land/x/chomp/utility/check-source.ts";
-
-const checker = new CheckSource(['./src'], { directories: 'my-directory' });
-await checker.run();
-
-
-
-
-
- - - - - - - - - - -
- -

Exclude a file

-
-
import { CheckSource } from "https://deno.land/x/chomp/utility/check-source.ts";
-
-const checker = new CheckSource(['./src'], { files: './src/my-directory/my-file.txt' });
-await checker.run();
-
-
-
-
-
-
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
CheckSource(paths: string[], exclusions?: ExclusionConfig) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

- - - - - - - - - - -
-
private
-
errors: number - -
- - - - -
-
- - - - - - - - - - -
-
private
-
files: string[] - -
- - - - -
-
-
-
- - - - - - - - - - -
-
private
-
addFile(path: string): void - -
- - - - -

Add file to array of files

-
-
- - - - - - - - - - -
-
private
-
checkFiles(): Promise<void> - -
- - - - -

Check all files found

-
-
- - - - - - - - - - -
-
private
-
getFiles(path: string): Promise<void> - -
- - - - -

Recursively can all files in the given path -Ignore directories and files given in our exclusions

-
-
- - - - - - - - - - -
- run(): Promise<void> - - - - - - -
-
-
-
-
-
-
-

Usage

import { CheckSource } from ".";
-
-
-
-
- - diff --git a/docs/~/CheckSource.prototype.addFile.html b/docs/~/CheckSource.prototype.addFile.html deleted file mode 100644 index 5394cd38..00000000 --- a/docs/~/CheckSource.prototype.addFile.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - CheckSource.prototype.addFile - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CheckSource.prototype.addFile -
- - - - -
-
- -

Add file to array of files

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- path: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { CheckSource } from ".";
-
-
-
-
- - diff --git a/docs/~/CheckSource.prototype.checkFiles.html b/docs/~/CheckSource.prototype.checkFiles.html deleted file mode 100644 index 81408c2b..00000000 --- a/docs/~/CheckSource.prototype.checkFiles.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - CheckSource.prototype.checkFiles - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CheckSource.prototype.checkFiles -
- - - - -
-
- -

Check all files found

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CheckSource } from ".";
-
-
-
-
- - diff --git a/docs/~/CheckSource.prototype.errors.html b/docs/~/CheckSource.prototype.errors.html deleted file mode 100644 index be0a3742..00000000 --- a/docs/~/CheckSource.prototype.errors.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - CheckSource.prototype.errors - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { CheckSource } from ".";
-
-
-
-
- - diff --git a/docs/~/CheckSource.prototype.files.html b/docs/~/CheckSource.prototype.files.html deleted file mode 100644 index 3b6f3a33..00000000 --- a/docs/~/CheckSource.prototype.files.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - CheckSource.prototype.files - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { CheckSource } from ".";
-
-
-
-
- - diff --git a/docs/~/CheckSource.prototype.getFiles.html b/docs/~/CheckSource.prototype.getFiles.html deleted file mode 100644 index f4f56cb0..00000000 --- a/docs/~/CheckSource.prototype.getFiles.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - CheckSource.prototype.getFiles - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CheckSource.prototype.getFiles -
- - - - -
-
- -

Recursively can all files in the given path -Ignore directories and files given in our exclusions

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- path: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CheckSource } from ".";
-
-
-
-
- - diff --git a/docs/~/CheckSource.prototype.html b/docs/~/CheckSource.prototype.html deleted file mode 100644 index 6249742a..00000000 --- a/docs/~/CheckSource.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/CheckSource.prototype.run.html b/docs/~/CheckSource.prototype.run.html deleted file mode 100644 index 9bb08b50..00000000 --- a/docs/~/CheckSource.prototype.run.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - CheckSource.prototype.run - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CheckSource.prototype.run -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CheckSource } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.check.html b/docs/~/Configure.check.html deleted file mode 100644 index d46a345b..00000000 --- a/docs/~/Configure.check.html +++ /dev/null @@ -1,321 +0,0 @@ - - - - Configure.check - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Configure.check -
- - - - -
-
- -

Return whether a key exists

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-const exists = Configure.check('my-item');
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- boolean - - - - - - -

boolean

-
-
-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.clear.html b/docs/~/Configure.clear.html deleted file mode 100644 index b753bd7b..00000000 --- a/docs/~/Configure.clear.html +++ /dev/null @@ -1,246 +0,0 @@ - - - - Configure.clear - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Configure.clear -
- - - - -
-
- -

Clear all items in the configure (including defaults). -If you want to keep the defaults, use Configure.reset() | Configure.reset() instead.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-Configure.clear();
-
-
-
-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- void - - - - - - -

void

-
-
-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.config.html b/docs/~/Configure.config.html deleted file mode 100644 index 4378f13e..00000000 --- a/docs/~/Configure.config.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Configure.config - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.consume.html b/docs/~/Configure.consume.html deleted file mode 100644 index 60db3fa3..00000000 --- a/docs/~/Configure.consume.html +++ /dev/null @@ -1,415 +0,0 @@ - - - - Configure.consume - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Configure.consume -
- - - - -
-
- -

Consume a key from configure (removing it).

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-const exists = Configure.consume('my-item');
-
-
-
-
-
- - - - - - - - - - -
- -

Setting a default value

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-const exists = Configure.consume('my-item', 'default-value');
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
defaultValue: any = null - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.delete.html b/docs/~/Configure.delete.html deleted file mode 100644 index 3738ae19..00000000 --- a/docs/~/Configure.delete.html +++ /dev/null @@ -1,321 +0,0 @@ - - - - Configure.delete - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Configure.delete -
- - - - -
-
- -

Delete a ConfigureItem from the Configure

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-Configure.delete('my-item');
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- void - - - - - - -

void

-
-
-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.dump.html b/docs/~/Configure.dump.html deleted file mode 100644 index 90a0dd8d..00000000 --- a/docs/~/Configure.dump.html +++ /dev/null @@ -1,245 +0,0 @@ - - - - Configure.dump - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Configure.dump -
- - - - -
-
- -

Dump all contents of the Configure

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-console.log(Configure.dump());
-
-
-
-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Map<string, any> - - - - - - -

ConfigureItem[]

-
-
-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.get.html b/docs/~/Configure.get.html deleted file mode 100644 index 30367aa1..00000000 --- a/docs/~/Configure.get.html +++ /dev/null @@ -1,418 +0,0 @@ - - - - Configure.get - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Configure.get -
- - - - -
-
- -

Obtain the value of a key in the configure.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-const item = Configure.get('my-item');
-
-
-
-
-
- - - - - - - - - - -
- -

Setting a default value

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-const item = Configure.get('my-item', 'my-default');
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -

Key to look for

-
-
- - - - - - - - - - -
-
optional
-
defaultValue: any = null - -
- - - - -

Default value to return when no result was found

-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- any | null - - - - - - -

any|null

-
-
-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.hasLoaded.html b/docs/~/Configure.hasLoaded.html deleted file mode 100644 index f293614c..00000000 --- a/docs/~/Configure.hasLoaded.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Configure.hasLoaded - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.html b/docs/~/Configure.html deleted file mode 100644 index 9069c210..00000000 --- a/docs/~/Configure.html +++ /dev/null @@ -1,705 +0,0 @@ - - - - Configure - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Configure -
- - - - -
-
-

- - - - - - - - - - -Static Properties

- - - - - - - - - - -
-
private
-
config: Map<string, any> - -
- - - - -
-
- - - - - - - - - - -
-
private
-
hasLoaded: boolean - -
- - - - -
-
-
-
-

- - - - - - - - - - -Static Methods

- - - - - - - - - - -
- check(key: string): boolean - - - - - - -

Return whether a key exists

-
-
- - - - - - - - - - -
- clear(): void - - - - - - -

Clear all items in the configure (including defaults). -If you want to keep the defaults, use Configure.reset() | Configure.reset() instead.

-
-
- - - - - - - - - - -
- consume(key: string, defaultValue?: any): any - - - - - - -

Consume a key from configure (removing it).

-
-
- - - - - - - - - - -
- delete(key: string): void - - - - - - -

Delete a ConfigureItem from the Configure

-
-
- - - - - - - - - - -
- dump(): Map<string, any> - - - - - - -

Dump all contents of the Configure

-
-
- - - - - - - - - - -
- get(key: string, defaultValue?: any): any | null - - - - - - -

Obtain the value of a key in the configure.

-
-
- - - - - - - - - - -
- load(force?: boolean): Promise<void> - - - - - - -

Load our configure data from file

-
-
- - - - - - - - - - -
- reset(): void - - - - - - -

Resets the configure to the defaults. -If you do not want to keep the defaults, use "Configure.clear()" instead.

-
-
- - - - - - - - - - -
- set(key: string, value: any): void - - - - - - -

Set a configure item -It is not possible to store null values

-
-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.load.html b/docs/~/Configure.load.html deleted file mode 100644 index 70b1f43a..00000000 --- a/docs/~/Configure.load.html +++ /dev/null @@ -1,321 +0,0 @@ - - - - Configure.load - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Configure.load -
- - - - -
-
- -

Load our configure data from file

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
-
optional
-
force: boolean = false - -
- - - - -

Set to true to force re-loading the configure

-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -

void

-
-
-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.prototype.html b/docs/~/Configure.prototype.html deleted file mode 100644 index ccaf5c3a..00000000 --- a/docs/~/Configure.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Configure.reset.html b/docs/~/Configure.reset.html deleted file mode 100644 index 49087331..00000000 --- a/docs/~/Configure.reset.html +++ /dev/null @@ -1,245 +0,0 @@ - - - - Configure.reset - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Configure.reset -
- - - - -
-
- -

Resets the configure to the defaults. -If you do not want to keep the defaults, use "Configure.clear()" instead.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-Configure.reset();
-
-
-
-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Configure.set.html b/docs/~/Configure.set.html deleted file mode 100644 index 302a4329..00000000 --- a/docs/~/Configure.set.html +++ /dev/null @@ -1,373 +0,0 @@ - - - - Configure.set - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Configure.set -
- - - - -
-
- -

Set a configure item -It is not possible to store null values

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Configure } from "https://deno.land/x/chomp/core/configure.ts";
-
-await Configure.load();
-Configure.set('my-item', 'my-value);
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
- - - - - - - - - - -
- value: any - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- void - - - - - - -

void

-
-
-
-
-
-
-
-
-

Usage

import { Configure } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller._componentDir.html b/docs/~/Controller._componentDir.html deleted file mode 100644 index 85542aca..00000000 --- a/docs/~/Controller._componentDir.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Controller._componentDir - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller._templateDir.html b/docs/~/Controller._templateDir.html deleted file mode 100644 index 2caa32f9..00000000 --- a/docs/~/Controller._templateDir.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Controller._templateDir - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.html b/docs/~/Controller.html deleted file mode 100644 index 96b543ab..00000000 --- a/docs/~/Controller.html +++ /dev/null @@ -1,813 +0,0 @@ - - - - Controller - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Controller -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
Controller(request: Request) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

- - - - - - - - - - -
-
deprecated
-
writeonly
-
type - -
- - - - -

Set the 'Content-Type' header

-
-
- - - - - - - - - - -
-
private
-
_response: ResponseBuilder - -
- - - - -
- -
-
-
- - - - - - - - - - -
-
protected
-
getRequest(): Request - -
- - - - -

Get the request object for this controller

-
-
- - - - - - - - - - -
-
protected
-
getResponse(): ResponseBuilder - -
- - - - -

Get the response object for this controller

-
-
- - - - - - - - - - -
- initialize(): Promise<void> - - - - - - -

Initialize the controller. -Literally does nothing at this moment except exist to prevent errors.

-
-
- - - - - - - - - - -
-
protected
-
loadComponent(name: string): Promise<Controller> - -
- - - - -
-
- - - - - - - - - - -
- render(): Promise<void> - - - - - - -

Render the page output -Will try to decide the best way of doing it based on the MIME set

-
-
- - - - - - - - - - -
-
protected
-
set(key: string, value: string | number | unknown): void - -
- - - - -

Set a view variable

-
-
-
-
-

- - - - - - - - - - -Static Properties

- - - - - - - - - - -
-
readonly
-
private
-
_componentDir: string - -
- - - - -
-
- - - - - - - - - - -
-
private
-
readonly
-
_templateDir: `./src/templates` - -
- - - - -
-
-
-
-
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.prototype._response.html b/docs/~/Controller.prototype._response.html deleted file mode 100644 index 6d801215..00000000 --- a/docs/~/Controller.prototype._response.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Controller.prototype._response - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.prototype._vars.html b/docs/~/Controller.prototype._vars.html deleted file mode 100644 index c90a659c..00000000 --- a/docs/~/Controller.prototype._vars.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Controller.prototype._vars - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.prototype.getRequest.html b/docs/~/Controller.prototype.getRequest.html deleted file mode 100644 index fe681c2c..00000000 --- a/docs/~/Controller.prototype.getRequest.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - Controller.prototype.getRequest - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Controller.prototype.getRequest -
- - - - -
-
- -

Get the request object for this controller

-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.prototype.getResponse.html b/docs/~/Controller.prototype.getResponse.html deleted file mode 100644 index 233efbf0..00000000 --- a/docs/~/Controller.prototype.getResponse.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - Controller.prototype.getResponse - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Controller.prototype.getResponse -
- - - - -
-
- -

Get the response object for this controller

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- ResponseBuilder - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.prototype.html b/docs/~/Controller.prototype.html deleted file mode 100644 index c4b24f21..00000000 --- a/docs/~/Controller.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Controller.prototype.initialize.html b/docs/~/Controller.prototype.initialize.html deleted file mode 100644 index 86757e9e..00000000 --- a/docs/~/Controller.prototype.initialize.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - Controller.prototype.initialize - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Controller.prototype.initialize -
- - - - -
-
- -

Initialize the controller. -Literally does nothing at this moment except exist to prevent errors.

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.prototype.loadComponent.html b/docs/~/Controller.prototype.loadComponent.html deleted file mode 100644 index ab38a0c7..00000000 --- a/docs/~/Controller.prototype.loadComponent.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Controller.prototype.loadComponent - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Controller.prototype.loadComponent -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- name: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.prototype.render.html b/docs/~/Controller.prototype.render.html deleted file mode 100644 index f8f1c644..00000000 --- a/docs/~/Controller.prototype.render.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - Controller.prototype.render - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Controller.prototype.render -
- - - - -
-
- -

Render the page output -Will try to decide the best way of doing it based on the MIME set

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -

Promise

-
-
-
-
-
-
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.prototype.set.html b/docs/~/Controller.prototype.set.html deleted file mode 100644 index c81482cc..00000000 --- a/docs/~/Controller.prototype.set.html +++ /dev/null @@ -1,303 +0,0 @@ - - - - Controller.prototype.set - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Controller.prototype.set -
- - - - -
-
- -

Set a view variable

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
- - - - - - - - - - -
- value: string | number | unknown - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/Controller.prototype.type.html b/docs/~/Controller.prototype.type.html deleted file mode 100644 index af81df76..00000000 --- a/docs/~/Controller.prototype.type.html +++ /dev/null @@ -1,255 +0,0 @@ - - - - Controller.prototype.type - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Controller.prototype.type -
- - - - -
-
- -

Set the 'Content-Type' header

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
-
optional
-
value: string = text/html - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Controller } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.html b/docs/~/CouchDB.html deleted file mode 100644 index cad74240..00000000 --- a/docs/~/CouchDB.html +++ /dev/null @@ -1,739 +0,0 @@ - - - - CouchDB - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class CouchDB -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
CouchDB(host?: string, database: string, auth?: Auth) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

- - - - - - - - - - -
-
writeonly
-
password: string - -
- - - - -

Update the password for this instance. -This does not update the password on the server.

-
-
- - - - - - - - - - -
-
writeonly
-
username: string - -
- - - - -

Update the username for this instance. -This does not update the username on the server.

-
-
- - - - - - - - - - -
-
private
-
auth: string - -
- - - - -
-
-
-
- - - - - - - - - - -
- delete(id: string, revision: string): Promise<CouchResponse> - - - - - - -

Delete a document from the database. -TODO: Automatically find revision.

-
-
- - - - - - - - - - -
- get(id: string): Promise<CouchResponse> - - - - - - -

Get a document from the database.

-
-
- - - - - - - - - - -
- insert(data: any): Promise<CouchResponse> - - - - - - -

Insert a document into the database.

-

Any document passed to the method will be attempted to insert "as-is". -The more convenient "CouchDB.upsert() | CouchDB.upsert()" method should be used most of the time.

-
-
- - - - - - - - - - -
- raw(endpoint: string, body?: any, overrides?: CouchOverrides): Promise<CouchResponse> - - - - - - -

Main request handler. -This method is used for most of our other methods as well.

-
-
- - - - - - - - - - -
- update(id: string, revision: string, data: any): Promise<CouchResponse> - - - - - - -

Update a document in the database.

-

This is only useful if you know the latest revision. -The more convenient "CouchDB.upsert() | CouchDB.upsert()" should be used most of the time.

-
-
- - - - - - - - - - -
- upsert(id: string, data: any): Promise<CouchResponse> - - - - - - -

Update or insert a document into the database. -This method will automatically check if an existing document exists and try to update it. -If no document exists, it will be created instead.

-
-
- - - - - - - - - - -
- viewDesign(design: string, view: string, partition: string): Promise<CouchResponse> - - - - - - -

Execute a view design

-
-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.auth.html b/docs/~/CouchDB.prototype.auth.html deleted file mode 100644 index 3f187383..00000000 --- a/docs/~/CouchDB.prototype.auth.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - CouchDB.prototype.auth - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.delete.html b/docs/~/CouchDB.prototype.delete.html deleted file mode 100644 index 3f68753d..00000000 --- a/docs/~/CouchDB.prototype.delete.html +++ /dev/null @@ -1,384 +0,0 @@ - - - - CouchDB.prototype.delete - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CouchDB.prototype.delete -
- - - - -
-
- -

Delete a document from the database. -TODO: Automatically find revision.

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
-
-const couchdb = new CouchDB(...);
-const existing = await couchdb.get('my-key');
-if(existing.status === 404) return;
-const resp = await couchdb.delete('my-key', existing.data['_rev']);
-
-if(resp.status !== 200) {
-  // Handle deletion error
-}
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- id: string - - - - - - -
-
- - - - - - - - - - -
- revision: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<CouchResponse> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.get.html b/docs/~/CouchDB.prototype.get.html deleted file mode 100644 index dca75a15..00000000 --- a/docs/~/CouchDB.prototype.get.html +++ /dev/null @@ -1,328 +0,0 @@ - - - - CouchDB.prototype.get - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CouchDB.prototype.get -
- - - - -
-
- -

Get a document from the database.

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
-
-const couchdb = new CouchDB(...);
-const existing = await couchdb.get('my-key');
-
-if(existing.status === 404) {
-  // Handle non-existing document
-}
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- id: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<CouchResponse> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.html b/docs/~/CouchDB.prototype.html deleted file mode 100644 index 39b9f4ea..00000000 --- a/docs/~/CouchDB.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/CouchDB.prototype.insert.html b/docs/~/CouchDB.prototype.insert.html deleted file mode 100644 index 6e777bbf..00000000 --- a/docs/~/CouchDB.prototype.insert.html +++ /dev/null @@ -1,336 +0,0 @@ - - - - CouchDB.prototype.insert - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CouchDB.prototype.insert -
- - - - -
-
- -

Insert a document into the database.

-

Any document passed to the method will be attempted to insert "as-is". -The more convenient "CouchDB.upsert() | CouchDB.upsert()" method should be used most of the time.

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
-
-const couchdb = new CouchDB(...);
-const resp = await couchdb.insert({
-  '_id': 'my-key',
-  'data': 'my-data',
-});
-
-if(resp.status !== 201) {
-  // Handle insert error
-}
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- data: any - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<CouchResponse> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.password.html b/docs/~/CouchDB.prototype.password.html deleted file mode 100644 index a5ed3074..00000000 --- a/docs/~/CouchDB.prototype.password.html +++ /dev/null @@ -1,321 +0,0 @@ - - - - CouchDB.prototype.password - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CouchDB.prototype.password -
- - - - -
-
- -

Update the password for this instance. -This does not update the password on the server.

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
-
-const couchdb = new CouchDB();
-couchdb.password = 'lamepassword';
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- password: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.raw.html b/docs/~/CouchDB.prototype.raw.html deleted file mode 100644 index 65e73718..00000000 --- a/docs/~/CouchDB.prototype.raw.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - CouchDB.prototype.raw - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CouchDB.prototype.raw -
- - - - -
-
- -

Main request handler. -This method is used for most of our other methods as well.

-
-
- - - - - - - - - - -
- -

Example 1

-
-
// TODO: Write example
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- endpoint: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
body: any = null - -
- - - - -
-
- - - - - - - - - - -
-
optional
-
overrides: CouchOverrides = [UNSUPPORTED] - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<CouchResponse> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.update.html b/docs/~/CouchDB.prototype.update.html deleted file mode 100644 index 06115c28..00000000 --- a/docs/~/CouchDB.prototype.update.html +++ /dev/null @@ -1,432 +0,0 @@ - - - - CouchDB.prototype.update - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CouchDB.prototype.update -
- - - - -
-
- -

Update a document in the database.

-

This is only useful if you know the latest revision. -The more convenient "CouchDB.upsert() | CouchDB.upsert()" should be used most of the time.

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
-
-const couchdb = new CouchDB(...);
-const resp = await couchdb.update(`my-key`, '1-abcdef', 'my-data');
-
-if(resp.status !== 201) {
-  // Handle update error
-}
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- id: string - - - - - - -
-
- - - - - - - - - - -
- revision: string - - - - - - -
-
- - - - - - - - - - -
- data: any - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<CouchResponse> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.upsert.html b/docs/~/CouchDB.prototype.upsert.html deleted file mode 100644 index 17469575..00000000 --- a/docs/~/CouchDB.prototype.upsert.html +++ /dev/null @@ -1,381 +0,0 @@ - - - - CouchDB.prototype.upsert - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CouchDB.prototype.upsert -
- - - - -
-
- -

Update or insert a document into the database. -This method will automatically check if an existing document exists and try to update it. -If no document exists, it will be created instead.

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
-
-const couchdb = new CouchDB(...);
-const resp = await couchdb.upsert(`my-key`, 'my-data');
-
-if(resp.status !== 201) {
-  // Handle upsert error
-}
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- id: string - - - - - - -
-
- - - - - - - - - - -
- data: any - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<CouchResponse> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.username.html b/docs/~/CouchDB.prototype.username.html deleted file mode 100644 index da94c202..00000000 --- a/docs/~/CouchDB.prototype.username.html +++ /dev/null @@ -1,321 +0,0 @@ - - - - CouchDB.prototype.username - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CouchDB.prototype.username -
- - - - -
-
- -

Update the username for this instance. -This does not update the username on the server.

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
-
-const couchdb = new CouchDB();
-couchdb.username = 'couchuser';
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- username: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/CouchDB.prototype.viewDesign.html b/docs/~/CouchDB.prototype.viewDesign.html deleted file mode 100644 index cee42b7e..00000000 --- a/docs/~/CouchDB.prototype.viewDesign.html +++ /dev/null @@ -1,428 +0,0 @@ - - - - CouchDB.prototype.viewDesign - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method CouchDB.prototype.viewDesign -
- - - - -
-
- -

Execute a view design

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { CouchDB } from "https://deno.land/x/chomp/communication/couchdb.ts";
-
-const couchdb = new CouchDB(...);
-const resp = await couchdb.viewDesign('my-design', 'my-view', 'my-partition');
-if(resp.status !== 200) {
-  // Handle view error
-}
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- design: string - - - - - - -
-
- - - - - - - - - - -
- view: string - - - - - - -
-
- - - - - - - - - - -
- partition: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<CouchResponse> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { CouchDB } from ".";
-
-
-
-
- - diff --git a/docs/~/Cron.Cron.html b/docs/~/Cron.Cron.html deleted file mode 100644 index 66f6be69..00000000 --- a/docs/~/Cron.Cron.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - Cron.Cron - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- variable Cron.Cron -
- - - - -
-
-
-
-
-

Usage

import { Cron } from ".";
-const { Cron } = Cron;
-
-
-
-
- - diff --git a/docs/~/Cron.html b/docs/~/Cron.html deleted file mode 100644 index be8af1ec..00000000 --- a/docs/~/Cron.html +++ /dev/null @@ -1,379 +0,0 @@ - - - - Cron - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- function Cron -
- - - - -
-
- -

Cron entrypoint

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- pattern - - - - - - -
    -
  • Input pattern, input date, or input ISO 8601 time string
  • -
-
-
- - - - - - - - - - -
-
optional
-
fnOrOptions1 - -
- - - - -
    -
  • Options or function to be run each iteration of pattern
  • -
-
-
- - - - - - - - - - -
-
optional
-
fnOrOptions2 - -
- - - - -
    -
  • Options or function to be run each iteration of pattern
  • -
-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Cron } from ".";
-
-
-
-
- - diff --git a/docs/~/DEFAULT_OPTS.html b/docs/~/DEFAULT_OPTS.html deleted file mode 100644 index f129f071..00000000 --- a/docs/~/DEFAULT_OPTS.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - DEFAULT_OPTS - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { DEFAULT_OPTS } from ".";
-
-
-
-
- - diff --git a/docs/~/Druid.html b/docs/~/Druid.html deleted file mode 100644 index 52a29744..00000000 --- a/docs/~/Druid.html +++ /dev/null @@ -1,415 +0,0 @@ - - - - Druid - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Druid -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
Druid(host: string) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

- - - - - - - - - - -
-
writeonly
-
setSpec: any - -
- - - - -
-
- - - - - - - - - - -
-
readonly
-
getSpec: any - -
- - - - -
-
- - - - - - - - - - -
-
private
-
spec: any - -
- - - - -
-
-
-
- - - - - - - - - - -
- create(): Promise<Response> - - - - - - -

Create a new task in Apache Druid

-
-
-
-
-
-
-
-

Usage

import { Druid } from ".";
-
-
-
-
- - diff --git a/docs/~/Druid.prototype.create.html b/docs/~/Druid.prototype.create.html deleted file mode 100644 index f45e11ca..00000000 --- a/docs/~/Druid.prototype.create.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - Druid.prototype.create - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Druid.prototype.create -
- - - - -
-
- -

Create a new task in Apache Druid

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<Response> - - - - - - -

Promise

-
-
-
-
-
-
-
-
-

Usage

import { Druid } from ".";
-
-
-
-
- - diff --git a/docs/~/Druid.prototype.getSpec.html b/docs/~/Druid.prototype.getSpec.html deleted file mode 100644 index a1517c70..00000000 --- a/docs/~/Druid.prototype.getSpec.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Druid.prototype.getSpec - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Druid.prototype.getSpec -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Druid } from ".";
-
-
-
-
- - diff --git a/docs/~/Druid.prototype.html b/docs/~/Druid.prototype.html deleted file mode 100644 index c62f99d2..00000000 --- a/docs/~/Druid.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Druid.prototype.setSpec.html b/docs/~/Druid.prototype.setSpec.html deleted file mode 100644 index b395eac1..00000000 --- a/docs/~/Druid.prototype.setSpec.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Druid.prototype.setSpec - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Druid.prototype.setSpec -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- spec: any - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Druid } from ".";
-
-
-
-
- - diff --git a/docs/~/Druid.prototype.spec.html b/docs/~/Druid.prototype.spec.html deleted file mode 100644 index 5a8f6537..00000000 --- a/docs/~/Druid.prototype.spec.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Druid.prototype.spec - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Druid } from ".";
-
-
-
-
- - diff --git a/docs/~/ErrorCodes.html b/docs/~/ErrorCodes.html deleted file mode 100644 index 70975f40..00000000 --- a/docs/~/ErrorCodes.html +++ /dev/null @@ -1,1074 +0,0 @@ - - - - ErrorCodes - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- enum ErrorCodes -
- - - - -
-
- - - - - - - - - - -
- DEPRECATED_FUNCTION_CALL = 1 - - - - - - -
-
- - - - - - - - - - -
- FILE_READ_GENERIC = 528 - - - - - - -
-
- - - - - - - - - - -
- FILE_READ_NOT_FOUND = 529 - - - - - - -
-
- - - - - - - - - - -
- FILE_READ_NO_PERM = 530 - - - - - - -
-
- - - - - - - - - - -
- FILE_WRITE_GENERIC = 544 - - - - - - -
-
- - - - - - - - - - -
- FILE_WRITE_NOT_FOUND = 545 - - - - - - -
-
- - - - - - - - - - -
- FILE_WRITE_NO_PERM = 546 - - - - - - -
-
- - - - - - - - - - -
- UNKNOWN_ERROR = 0 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_BAD_GATEWAY = 3147010 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_BAD_REQUEST = 3146752 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_FORBIDDEN = 3146755 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_GATEWAY_TIMEOUT = 3147012 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_INTERNAL_SERVER_ERROR = 3147008 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_METHOD_NOT_ALLOWED = 3146757 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_NOT_FOUND = 3146756 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_REQUEST_TIMEOUT = 3146760 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_SERVICE_UNAVAILABLE = 3147011 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP_TOO_MANY_REQUESTS = 3146793 - - - - - - -
-
- - - - - - - - - - -
- UPSTREAM_HTTP__UNAUTHORIZED = 3146753 - - - - - - -
-
-
-
-
-
-
-

Usage

import { ErrorCodes } from ".";
-
-
-
-
- - diff --git a/docs/~/Events.add.html b/docs/~/Events.add.html deleted file mode 100644 index 601ac03b..00000000 --- a/docs/~/Events.add.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Events.add - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Events.add -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- event: IEvent - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Events } from ".";
-
-
-
-
- - diff --git a/docs/~/Events.dispatch.html b/docs/~/Events.dispatch.html deleted file mode 100644 index e05fc1d6..00000000 --- a/docs/~/Events.dispatch.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - Events.dispatch - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Events.dispatch -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- event: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
data: any = [UNSUPPORTED] - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Events } from ".";
-
-
-
-
- - diff --git a/docs/~/Events.getEvents.html b/docs/~/Events.getEvents.html deleted file mode 100644 index f0b4b31f..00000000 --- a/docs/~/Events.getEvents.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Events.getEvents - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Events.getEvents -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Events } from ".";
-
-
-
-
- - diff --git a/docs/~/Events.getHandler.html b/docs/~/Events.getHandler.html deleted file mode 100644 index a83d7ffe..00000000 --- a/docs/~/Events.getHandler.html +++ /dev/null @@ -1,200 +0,0 @@ - - - - Events.getHandler - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Events.getHandler -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- name: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Events } from ".";
-
-
-
-
- - diff --git a/docs/~/Events.handlers.html b/docs/~/Events.handlers.html deleted file mode 100644 index ae0c77b7..00000000 --- a/docs/~/Events.handlers.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Events.handlers - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Events } from ".";
-
-
-
-
- - diff --git a/docs/~/Events.html b/docs/~/Events.html deleted file mode 100644 index 4e37f837..00000000 --- a/docs/~/Events.html +++ /dev/null @@ -1,438 +0,0 @@ - - - - Events - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Events -
- - - - -
-
-

- - - - - - - - - - -Static Properties

- - - - - - - - - - -
-
private
-
handlers: any - -
- - - - -
-
- - - - - - - - - - -
-
private
-
list: IEvent[] - -
- - - - -
-
-
-
-

- - - - - - - - - - -Static Methods

- - - - - - - - - - -
- add(event: IEvent): Promise<void> - - - - - - -
-
- - - - - - - - - - -
- dispatch(event: string, data?: any) - - - - - - -
- - -
-
-
-
-
-
-

Usage

import { Events } from ".";
-
-
-
-
- - diff --git a/docs/~/Events.list.html b/docs/~/Events.list.html deleted file mode 100644 index 3b63cc1b..00000000 --- a/docs/~/Events.list.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Events.list - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Events } from ".";
-
-
-
-
- - diff --git a/docs/~/Events.prototype.html b/docs/~/Events.prototype.html deleted file mode 100644 index 9993d256..00000000 --- a/docs/~/Events.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/ExclusionConfig.directories.html b/docs/~/ExclusionConfig.directories.html deleted file mode 100644 index 5936a64b..00000000 --- a/docs/~/ExclusionConfig.directories.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - ExclusionConfig.directories - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { type ExclusionConfig } from ".";
-
-
-
-
- - diff --git a/docs/~/ExclusionConfig.files.html b/docs/~/ExclusionConfig.files.html deleted file mode 100644 index 94ef2aa3..00000000 --- a/docs/~/ExclusionConfig.files.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - ExclusionConfig.files - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { type ExclusionConfig } from ".";
-
-
-
-
- - diff --git a/docs/~/ExclusionConfig.html b/docs/~/ExclusionConfig.html deleted file mode 100644 index 07bc1105..00000000 --- a/docs/~/ExclusionConfig.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - ExclusionConfig - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { type ExclusionConfig } from ".";
-
-
-
-
- - diff --git a/docs/~/File.html b/docs/~/File.html deleted file mode 100644 index 4dec3735..00000000 --- a/docs/~/File.html +++ /dev/null @@ -1,488 +0,0 @@ - - - - File - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class File -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
File(path: string) - -
- - - - -
-
-
-
- - - - - - - - - - -
- create(): Promise<void> - - - - - - -
-
- - - - - - - - - - -
- delete(): Promise<void> - - - - - - -
-
- - - - - - - - - - -
- exists(): Promise<boolean> - - - - - - -
-
- - - - - - - - - - -
- ext(): string - - - - - - -
- - -
-
-
-
-
-
-

Usage

import { File } from ".";
-
-
-
-
- - diff --git a/docs/~/File.prototype.create.html b/docs/~/File.prototype.create.html deleted file mode 100644 index 6a0a28b4..00000000 --- a/docs/~/File.prototype.create.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - File.prototype.create - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method File.prototype.create -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { File } from ".";
-
-
-
-
- - diff --git a/docs/~/File.prototype.delete.html b/docs/~/File.prototype.delete.html deleted file mode 100644 index c8c9e8d7..00000000 --- a/docs/~/File.prototype.delete.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - File.prototype.delete - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method File.prototype.delete -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { File } from ".";
-
-
-
-
- - diff --git a/docs/~/File.prototype.exists.html b/docs/~/File.prototype.exists.html deleted file mode 100644 index 577dc38b..00000000 --- a/docs/~/File.prototype.exists.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - File.prototype.exists - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method File.prototype.exists -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<boolean> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { File } from ".";
-
-
-
-
- - diff --git a/docs/~/File.prototype.ext.html b/docs/~/File.prototype.ext.html deleted file mode 100644 index 5b3a075c..00000000 --- a/docs/~/File.prototype.ext.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - File.prototype.ext - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method File.prototype.ext -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { File } from ".";
-
-
-
-
- - diff --git a/docs/~/File.prototype.html b/docs/~/File.prototype.html deleted file mode 100644 index 75694429..00000000 --- a/docs/~/File.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/File.prototype.readFile.html b/docs/~/File.prototype.readFile.html deleted file mode 100644 index 2a4ac28d..00000000 --- a/docs/~/File.prototype.readFile.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - File.prototype.readFile - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method File.prototype.readFile -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { File } from ".";
-
-
-
-
- - diff --git a/docs/~/File.prototype.readTextFile.html b/docs/~/File.prototype.readTextFile.html deleted file mode 100644 index fc800386..00000000 --- a/docs/~/File.prototype.readTextFile.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - File.prototype.readTextFile - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method File.prototype.readTextFile -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { File } from ".";
-
-
-
-
- - diff --git a/docs/~/Folder.html b/docs/~/Folder.html deleted file mode 100644 index 53b0e6f6..00000000 --- a/docs/~/Folder.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - Folder - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Folder } from ".";
-
-
-
-
- - diff --git a/docs/~/Folder.prototype.create.html b/docs/~/Folder.prototype.create.html deleted file mode 100644 index d22349bb..00000000 --- a/docs/~/Folder.prototype.create.html +++ /dev/null @@ -1,254 +0,0 @@ - - - - Folder.prototype.create - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Folder.prototype.create -
- - - - -
-
- -

Create the directory if it does not exist yet.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
-
optional
-
options: Deno.MkdirOptions - -
- - - - -

Options with which to create the directory

-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Folder } from ".";
-
-
-
-
- - diff --git a/docs/~/Folder.prototype.exists.html b/docs/~/Folder.prototype.exists.html deleted file mode 100644 index 81e5f65f..00000000 --- a/docs/~/Folder.prototype.exists.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - Folder.prototype.exists - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Folder.prototype.exists -
- - - - -
-
- -

Check whether the folder exists at the path.

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<boolean> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Folder } from ".";
-
-
-
-
- - diff --git a/docs/~/Folder.prototype.html b/docs/~/Folder.prototype.html deleted file mode 100644 index d76968ff..00000000 --- a/docs/~/Folder.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/GraphQL.html b/docs/~/GraphQL.html deleted file mode 100644 index 355c2a49..00000000 --- a/docs/~/GraphQL.html +++ /dev/null @@ -1,466 +0,0 @@ - - - - GraphQL - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class GraphQL -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
GraphQL(endpoint?: string) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

- - - - - - - - - - -
-
private
-
_query: string - -
- - - - -
- -
-
-
- - - - - - - - - - -
- addVariable(key: string, value: string): GraphQL - - - - - - -

Add a variable to our variables object

-
- -
- - - - - - - - - - -
- setQuery(query: string): GraphQL - - - - - - -

Set our query string

-
-
-
-
-
-
-
-

Usage

import { GraphQL } from ".";
-
-
-
-
- - diff --git a/docs/~/GraphQL.prototype._query.html b/docs/~/GraphQL.prototype._query.html deleted file mode 100644 index 3fb4ee03..00000000 --- a/docs/~/GraphQL.prototype._query.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - GraphQL.prototype._query - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { GraphQL } from ".";
-
-
-
-
- - diff --git a/docs/~/GraphQL.prototype._variables.html b/docs/~/GraphQL.prototype._variables.html deleted file mode 100644 index 8dc57af4..00000000 --- a/docs/~/GraphQL.prototype._variables.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - GraphQL.prototype._variables - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- property GraphQL.prototype._variables -
- - - - -
-
-
-
-
-

Usage

import { GraphQL } from ".";
-
-
-
-
- - diff --git a/docs/~/GraphQL.prototype.addVariable.html b/docs/~/GraphQL.prototype.addVariable.html deleted file mode 100644 index 0912f362..00000000 --- a/docs/~/GraphQL.prototype.addVariable.html +++ /dev/null @@ -1,304 +0,0 @@ - - - - GraphQL.prototype.addVariable - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method GraphQL.prototype.addVariable -
- - - - -
-
- -

Add a variable to our variables object

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- key: string - - - - - - -
-
- - - - - - - - - - -
- value: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -

The instance of this class

-
-
-
-
-
-
-
-
-

Usage

import { GraphQL } from ".";
-
-
-
-
- - diff --git a/docs/~/GraphQL.prototype.execute.html b/docs/~/GraphQL.prototype.execute.html deleted file mode 100644 index f7b44327..00000000 --- a/docs/~/GraphQL.prototype.execute.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - GraphQL.prototype.execute - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method GraphQL.prototype.execute -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { GraphQL } from ".";
-
-
-
-
- - diff --git a/docs/~/GraphQL.prototype.html b/docs/~/GraphQL.prototype.html deleted file mode 100644 index 55bc4c5b..00000000 --- a/docs/~/GraphQL.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/GraphQL.prototype.setQuery.html b/docs/~/GraphQL.prototype.setQuery.html deleted file mode 100644 index 3cd577dd..00000000 --- a/docs/~/GraphQL.prototype.setQuery.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - GraphQL.prototype.setQuery - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method GraphQL.prototype.setQuery -
- - - - -
-
- -

Set our query string

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- query: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -

The instance of this class

-
-
-
-
-
-
-
-
-

Usage

import { GraphQL } from ".";
-
-
-
-
- - diff --git a/docs/~/Hash.html b/docs/~/Hash.html deleted file mode 100644 index e2c5c9aa..00000000 --- a/docs/~/Hash.html +++ /dev/null @@ -1,363 +0,0 @@ - - - - Hash - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Hash } from ".";
-
-
-
-
- - diff --git a/docs/~/Hash.prototype.digest.html b/docs/~/Hash.prototype.digest.html deleted file mode 100644 index ae829173..00000000 --- a/docs/~/Hash.prototype.digest.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - Hash.prototype.digest - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Hash.prototype.digest -
- - - - -
-
- -

Digest the input

-
-
- - - - - - - - - - -
- -

Basic usage

-
-
import { Hash } from "https://deno.land/x/chomp/security/hash.ts";
-
-const hash = new Hash("some data");
-await hash.digest();
-console.log(hash.hex());
-
-
-
-
-
- - - - - - - - - - -
- -

Using BLAKE2B384

-
-
import { Hash, Algorithms } from "https://deno.land/x/chomp/security/hash.ts";
-
-const hash = new Hash("some data", Algorithms.BLAKE2B384);
-await hash.digest();
-
-
-
-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Hash } from ".";
-
-
-
-
- - diff --git a/docs/~/Hash.prototype.hex.html b/docs/~/Hash.prototype.hex.html deleted file mode 100644 index 593ce811..00000000 --- a/docs/~/Hash.prototype.hex.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - Hash.prototype.hex - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Hash.prototype.hex -
- - - - -
-
- -

Digest the input

-
-
- - - - - - - - - - -
- -

Basic usage

-
-
import { Hash } from "https://deno.land/x/chomp/security/hash.ts";
-
-const hash = new Hash("some data");
-await hash.digest();
-console.log(hash.hex());
-
-
-
-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Hash } from ".";
-
-
-
-
- - diff --git a/docs/~/Hash.prototype.html b/docs/~/Hash.prototype.html deleted file mode 100644 index dbe99667..00000000 --- a/docs/~/Hash.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Hash.prototype.result.html b/docs/~/Hash.prototype.result.html deleted file mode 100644 index d5593336..00000000 --- a/docs/~/Hash.prototype.result.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Hash.prototype.result - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Hash } from ".";
-
-
-
-
- - diff --git a/docs/~/INSECURE_ALGORITHMS.html b/docs/~/INSECURE_ALGORITHMS.html deleted file mode 100644 index 4ca39a8a..00000000 --- a/docs/~/INSECURE_ALGORITHMS.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - INSECURE_ALGORITHMS - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { INSECURE_ALGORITHMS } from ".";
-
-
-
-
- - diff --git a/docs/~/Inflector.camelize.html b/docs/~/Inflector.camelize.html deleted file mode 100644 index b6f624b4..00000000 --- a/docs/~/Inflector.camelize.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - Inflector.camelize - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Inflector.camelize -
- - - - -
-
- -

Turn a string into camelCase

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- input: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
delimiter: string = _ - -
- - - - -

Optional delimiter by which to split the string

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Inflector } from ".";
-
-
-
-
- - diff --git a/docs/~/Inflector.html b/docs/~/Inflector.html deleted file mode 100644 index f961fc56..00000000 --- a/docs/~/Inflector.html +++ /dev/null @@ -1,367 +0,0 @@ - - - - Inflector - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Inflector -
- - - - -

Idea and code primarily based on CakePHP's code.

-
-
-

- - - - - - - - - - -Static Methods

- - - - - - - - - - -
- camelize(input: string, delimiter?: string): string - - - - - - -

Turn a string into camelCase

-
-
- - - - - - - - - - -
- humanize(input: string, delimiter?: string): string - - - - - - -

Return the input lower_case_delimited_string as "A Human Readable String". -(Underscores are replaced by spaces and capitalized following words.)

-
-
- - - - - - - - - - -
- lcfirst(input: string): string - - - - - - -

Return input string with first character lowercased.

-
-
- - - - - - - - - - -
- pascalize(input: string, delimiter?: string): string - - - - - - -

Turn a string into PascalCase.

-
-
- - - - - - - - - - -
- ucfirst(input: string): string - - - - - - -

Return input string with first character uppercased.

-
-
-
-
-
-
-
-

Usage

import { Inflector } from ".";
-
-
-
-
- - diff --git a/docs/~/Inflector.humanize.html b/docs/~/Inflector.humanize.html deleted file mode 100644 index 6944ae52..00000000 --- a/docs/~/Inflector.humanize.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - Inflector.humanize - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Inflector.humanize -
- - - - -
-
- -

Return the input lower_case_delimited_string as "A Human Readable String". -(Underscores are replaced by spaces and capitalized following words.)

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- input: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
delimiter: string = _ - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Inflector } from ".";
-
-
-
-
- - diff --git a/docs/~/Inflector.lcfirst.html b/docs/~/Inflector.lcfirst.html deleted file mode 100644 index 349fde4a..00000000 --- a/docs/~/Inflector.lcfirst.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - Inflector.lcfirst - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Inflector.lcfirst -
- - - - -
-
- -

Return input string with first character lowercased.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- input: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Inflector } from ".";
-
-
-
-
- - diff --git a/docs/~/Inflector.pascalize.html b/docs/~/Inflector.pascalize.html deleted file mode 100644 index 4f94149f..00000000 --- a/docs/~/Inflector.pascalize.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - Inflector.pascalize - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Inflector.pascalize -
- - - - -
-
- -

Turn a string into PascalCase.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- input: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
delimiter: string = _ - -
- - - - -

Optional delimiter by which to split the string

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Inflector } from ".";
-
-
-
-
- - diff --git a/docs/~/Inflector.prototype.html b/docs/~/Inflector.prototype.html deleted file mode 100644 index a8910a9f..00000000 --- a/docs/~/Inflector.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Inflector.ucfirst.html b/docs/~/Inflector.ucfirst.html deleted file mode 100644 index f98d82ab..00000000 --- a/docs/~/Inflector.ucfirst.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - Inflector.ucfirst - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Inflector.ucfirst -
- - - - -
-
- -

Return input string with first character uppercased.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- input: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Inflector } from ".";
-
-
-
-
- - diff --git a/docs/~/InfluxDB.html b/docs/~/InfluxDB.html deleted file mode 100644 index 63eb3a6a..00000000 --- a/docs/~/InfluxDB.html +++ /dev/null @@ -1,362 +0,0 @@ - - - - InfluxDB - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class InfluxDB -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
InfluxDB(url: string, token: string) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

- - - - - - - - - - -
-
private
-
_api: Api - -
- - - - -
-
-
-
- - - - - - - - - - -
- setApi(org: string, bucket: string, precision?: Precision): this - - - - - - -
-
- - - - - - - - - - -
- write(data: Point | Point[]): Promise<boolean> - - - - - - -

Write our datapoint(s) to InfluxDB

-
-
-
-
-
-
-
-

Usage

import { InfluxDB } from ".";
-
-
-
-
- - diff --git a/docs/~/InfluxDB.prototype._api.html b/docs/~/InfluxDB.prototype._api.html deleted file mode 100644 index 51f83cb5..00000000 --- a/docs/~/InfluxDB.prototype._api.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - InfluxDB.prototype._api - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { InfluxDB } from ".";
-
-
-
-
- - diff --git a/docs/~/InfluxDB.prototype.html b/docs/~/InfluxDB.prototype.html deleted file mode 100644 index 9fd60992..00000000 --- a/docs/~/InfluxDB.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/InfluxDB.prototype.setApi.html b/docs/~/InfluxDB.prototype.setApi.html deleted file mode 100644 index 156c48bf..00000000 --- a/docs/~/InfluxDB.prototype.setApi.html +++ /dev/null @@ -1,354 +0,0 @@ - - - - InfluxDB.prototype.setApi - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method InfluxDB.prototype.setApi -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- org: string - - - - - - -
-
- - - - - - - - - - -
- bucket: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
precision: Precision = [Precision.us] - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { InfluxDB } from ".";
-
-
-
-
- - diff --git a/docs/~/InfluxDB.prototype.write.html b/docs/~/InfluxDB.prototype.write.html deleted file mode 100644 index ddc4997b..00000000 --- a/docs/~/InfluxDB.prototype.write.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - InfluxDB.prototype.write - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method InfluxDB.prototype.write -
- - - - -
-
- -

Write our datapoint(s) to InfluxDB

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- data: Point | Point[] - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<boolean> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { InfluxDB } from ".";
-
-
-
-
- - diff --git a/docs/~/Logger._handlers.html b/docs/~/Logger._handlers.html deleted file mode 100644 index 176ab9b8..00000000 --- a/docs/~/Logger._handlers.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Logger._handlers - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Logger } from ".";
-
-
-
-
- - diff --git a/docs/~/Logger.debug.html b/docs/~/Logger.debug.html deleted file mode 100644 index daebd0c3..00000000 --- a/docs/~/Logger.debug.html +++ /dev/null @@ -1,254 +0,0 @@ - - - - Logger.debug - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Logger.debug -
- - - - -
-
- -

Write a debug message to the console -Only shows up when the "DEBUG" env is set to truthy

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- message: string - - - - - - -

The message to write

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Logger } from ".";
-
-
-
-
- - diff --git a/docs/~/Logger.error.html b/docs/~/Logger.error.html deleted file mode 100644 index 1c17fe0a..00000000 --- a/docs/~/Logger.error.html +++ /dev/null @@ -1,307 +0,0 @@ - - - - Logger.error - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Logger.error -
- - - - -
-
- -

Write an error message to the console. -If the "error_log" Configure item is set, will also write to file.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- message: string - - - - - - -

The message to write

-
-
- - - - - - - - - - -
-
optional
-
stack: string | null = null - -
- - - - -

Optional stacktrace

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Logger } from ".";
-
-
-
-
- - diff --git a/docs/~/Logger.html b/docs/~/Logger.html deleted file mode 100644 index 62ca5898..00000000 --- a/docs/~/Logger.html +++ /dev/null @@ -1,499 +0,0 @@ - - - - Logger - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Logger -
- - - - -
-
-

- - - - - - - - - - -Static Properties

- - - - - - - - - - -
-
private
-
_handlers: Handlers - -
- - - - -
-
-
-
-

- - - - - - - - - - -Static Methods

- - - - - - - - - - -
- debug(message: string): void - - - - - - -

Write a debug message to the console -Only shows up when the "DEBUG" env is set to truthy

-
-
- - - - - - - - - - -
- error(message: string, stack?: string | null): void - - - - - - -

Write an error message to the console. -If the "error_log" Configure item is set, will also write to file.

-
-
- - - - - - - - - - -
- info(message: string): void - - - - - - -

Write an info message to the console

-
-
- - - - - - - - - - -
- setHandler(level: LogLevels, handler: Function): void - - - - - - -

Override a handler app-wide.

-
-
- - - - - - - - - - -
- time(): string - - - - - - -

Return the current time in format. -Configurable using the "logger.timeformat" key. -Defaults to "yyyy/MM/dd HH:mm:ss" (2020/11/28 20:50:30) -https://github.com/denoland/deno_std/tree/0.77.0/datetime#datetime

-
-
- - - - - - - - - - -
- warning(message: string): void - - - - - - -

Write a warning message to the console

-
-
-
-
-
-
-
-

Usage

import { Logger } from ".";
-
-
-
-
- - diff --git a/docs/~/Logger.info.html b/docs/~/Logger.info.html deleted file mode 100644 index 89354aa4..00000000 --- a/docs/~/Logger.info.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - Logger.info - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Logger.info -
- - - - -
-
- -

Write an info message to the console

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- message: string - - - - - - -

The message to write

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Logger } from ".";
-
-
-
-
- - diff --git a/docs/~/Logger.prototype.html b/docs/~/Logger.prototype.html deleted file mode 100644 index e45b1963..00000000 --- a/docs/~/Logger.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Logger.setHandler.html b/docs/~/Logger.setHandler.html deleted file mode 100644 index 236e50e0..00000000 --- a/docs/~/Logger.setHandler.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - Logger.setHandler - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Logger.setHandler -
- - - - -
-
- -

Override a handler app-wide.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- level: LogLevels - - - - - - -

{LogLevels}

-
-
- - - - - - - - - - -
- handler: Function - - - - - - -

{any}

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Logger } from ".";
-
-
-
-
- - diff --git a/docs/~/Logger.time.html b/docs/~/Logger.time.html deleted file mode 100644 index 3124f34c..00000000 --- a/docs/~/Logger.time.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - Logger.time - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Logger.time -
- - - - -
-
- -

Return the current time in format. -Configurable using the "logger.timeformat" key. -Defaults to "yyyy/MM/dd HH:mm:ss" (2020/11/28 20:50:30) -https://github.com/denoland/deno_std/tree/0.77.0/datetime#datetime

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- string - - - - - - -

The formatted time

-
-
-
-
-
-
-
-
-

Usage

import { Logger } from ".";
-
-
-
-
- - diff --git a/docs/~/Logger.warning.html b/docs/~/Logger.warning.html deleted file mode 100644 index 857ce18c..00000000 --- a/docs/~/Logger.warning.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - Logger.warning - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Logger.warning -
- - - - -
-
- -

Write a warning message to the console

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- message: string - - - - - - -

The message to write

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Logger } from ".";
-
-
-
-
- - diff --git a/docs/~/Loki.html b/docs/~/Loki.html deleted file mode 100644 index d5e18512..00000000 --- a/docs/~/Loki.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - Loki - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Loki } from ".";
-
-
-
-
- - diff --git a/docs/~/Loki.prototype.html b/docs/~/Loki.prototype.html deleted file mode 100644 index 835538bb..00000000 --- a/docs/~/Loki.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Loki.prototype.send.html b/docs/~/Loki.prototype.send.html deleted file mode 100644 index 99600318..00000000 --- a/docs/~/Loki.prototype.send.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - Loki.prototype.send - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Loki.prototype.send -
- - - - -
-
- -

Send a log entry to the Grafana Loki database.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- stream: LokiStream | LokiStream[] - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Loki } from ".";
-
-
-
-
- - diff --git a/docs/~/Ntfy.html b/docs/~/Ntfy.html deleted file mode 100644 index d9bd15ed..00000000 --- a/docs/~/Ntfy.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - Ntfy - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Ntfy } from ".";
-
-
-
-
- - diff --git a/docs/~/Ntfy.prototype.html b/docs/~/Ntfy.prototype.html deleted file mode 100644 index 8322424f..00000000 --- a/docs/~/Ntfy.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Ntfy.prototype.send.html b/docs/~/Ntfy.prototype.send.html deleted file mode 100644 index 9673ac29..00000000 --- a/docs/~/Ntfy.prototype.send.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - Ntfy.prototype.send - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Ntfy.prototype.send -
- - - - -
-
- -

Send a notification through Ntfy

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- message: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Ntfy } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.html b/docs/~/Nut.html deleted file mode 100644 index ddbae8aa..00000000 --- a/docs/~/Nut.html +++ /dev/null @@ -1,1083 +0,0 @@ - - - - Nut - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Nut -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
Nut(host: string | undefined, port?: number) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

-
- - - - - - - - - - -
-
readonly
-
status: number - -
- - - - -
-
- - - - - - - - - - -
-
private
-
_status: number - -
- - - - -
-
- - - - - - - - - - -
-
private
-
callback: any - -
- - - - -
- -
- - - - - - - - - - -
-
private
-
dataBuf: string - -
- - - - -
-
- - - - - - - - - - -
-
private
-
host: string - -
- - - - -
-
- - - - - - - - - - -
-
private
-
port: number - -
- - - - -
-
-
-
-
- - - - - - - - - - -
- connect(): Promise<void> - - - - - - -
-
- - - - - - - - - - -
- getCharge(name: string | undefined): Promise<number> - - - - - - -
-
- - - - - - - - - - -
- getLoad(name: string | undefined): Promise<number> - - - - - - -
-
- - - - - - - - - - -
- getPowerLimit(name: string | undefined): Promise<number> - - - - - - -
-
- - - - - - - - - - -
- getRuntime(name: string | undefined): Promise<number> - - - - - - -
-
- - - - - - - - - - -
- getStatus(name: string | undefined): Promise<string> - - - - - - -
-
- - - - - - - - - - -
-
private
-
onReceive(): Promise<void> - -
- - - - -
-
- - - - - - - - - - -
- send(cmd: string, callback: any): Promise<void> - - - - - - -
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.UPSList.html b/docs/~/Nut.prototype.UPSList.html deleted file mode 100644 index 839f5967..00000000 --- a/docs/~/Nut.prototype.UPSList.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Nut.prototype.UPSList - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.UPSList -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype._status.html b/docs/~/Nut.prototype._status.html deleted file mode 100644 index 52fc5c10..00000000 --- a/docs/~/Nut.prototype._status.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Nut.prototype._status - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.callback.html b/docs/~/Nut.prototype.callback.html deleted file mode 100644 index 339beb50..00000000 --- a/docs/~/Nut.prototype.callback.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Nut.prototype.callback - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.client.html b/docs/~/Nut.prototype.client.html deleted file mode 100644 index fbeeb54b..00000000 --- a/docs/~/Nut.prototype.client.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Nut.prototype.client - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.close.html b/docs/~/Nut.prototype.close.html deleted file mode 100644 index 635ed6c7..00000000 --- a/docs/~/Nut.prototype.close.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Nut.prototype.close - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.close -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.connect.html b/docs/~/Nut.prototype.connect.html deleted file mode 100644 index a16cab35..00000000 --- a/docs/~/Nut.prototype.connect.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Nut.prototype.connect - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.connect -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.dataBuf.html b/docs/~/Nut.prototype.dataBuf.html deleted file mode 100644 index 52d1f26a..00000000 --- a/docs/~/Nut.prototype.dataBuf.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Nut.prototype.dataBuf - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.getCharge.html b/docs/~/Nut.prototype.getCharge.html deleted file mode 100644 index ebdf1b5e..00000000 --- a/docs/~/Nut.prototype.getCharge.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Nut.prototype.getCharge - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.getCharge -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- name: string | undefined - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<number> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.getLoad.html b/docs/~/Nut.prototype.getLoad.html deleted file mode 100644 index 76d644fd..00000000 --- a/docs/~/Nut.prototype.getLoad.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Nut.prototype.getLoad - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.getLoad -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- name: string | undefined - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<number> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.getPowerLimit.html b/docs/~/Nut.prototype.getPowerLimit.html deleted file mode 100644 index 8d2737a1..00000000 --- a/docs/~/Nut.prototype.getPowerLimit.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Nut.prototype.getPowerLimit - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.getPowerLimit -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- name: string | undefined - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<number> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.getRuntime.html b/docs/~/Nut.prototype.getRuntime.html deleted file mode 100644 index 1183cc56..00000000 --- a/docs/~/Nut.prototype.getRuntime.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Nut.prototype.getRuntime - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.getRuntime -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- name: string | undefined - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<number> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.getStatus.html b/docs/~/Nut.prototype.getStatus.html deleted file mode 100644 index bfddaf31..00000000 --- a/docs/~/Nut.prototype.getStatus.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Nut.prototype.getStatus - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.getStatus -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- name: string | undefined - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<string> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.host.html b/docs/~/Nut.prototype.host.html deleted file mode 100644 index 2bf7efab..00000000 --- a/docs/~/Nut.prototype.host.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Nut.prototype.host - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.html b/docs/~/Nut.prototype.html deleted file mode 100644 index 57b9b336..00000000 --- a/docs/~/Nut.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Nut.prototype.onReceive.html b/docs/~/Nut.prototype.onReceive.html deleted file mode 100644 index d54074a0..00000000 --- a/docs/~/Nut.prototype.onReceive.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Nut.prototype.onReceive - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.onReceive -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.port.html b/docs/~/Nut.prototype.port.html deleted file mode 100644 index 7e3cd94e..00000000 --- a/docs/~/Nut.prototype.port.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Nut.prototype.port - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.send.html b/docs/~/Nut.prototype.send.html deleted file mode 100644 index 954eb17c..00000000 --- a/docs/~/Nut.prototype.send.html +++ /dev/null @@ -1,302 +0,0 @@ - - - - Nut.prototype.send - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.send -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- cmd: string - - - - - - -
-
- - - - - - - - - - -
- callback: any - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/Nut.prototype.status.html b/docs/~/Nut.prototype.status.html deleted file mode 100644 index 6e4ead9f..00000000 --- a/docs/~/Nut.prototype.status.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Nut.prototype.status - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Nut.prototype.status -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Nut } from ".";
-
-
-
-
- - diff --git a/docs/~/PASSWORD_DEFAULT.html b/docs/~/PASSWORD_DEFAULT.html deleted file mode 100644 index f96573d1..00000000 --- a/docs/~/PASSWORD_DEFAULT.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - PASSWORD_DEFAULT - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- variable PASSWORD_DEFAULT -
- - - - -

Recommended hashing algorithm for most use-cases. -May change over time to keep up with NIST approved algorithms

-
-
-
-
-
-

Usage

import { PASSWORD_DEFAULT } from ".";
-
-
-
-
- - diff --git a/docs/~/Password.doHash.html b/docs/~/Password.doHash.html deleted file mode 100644 index da03b5f6..00000000 --- a/docs/~/Password.doHash.html +++ /dev/null @@ -1,404 +0,0 @@ - - - - Password.doHash - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Password.doHash -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- input: string - - - - - - -
-
- - - - - - - - - - -
- algo: string - - - - - - -
-
- - - - - - - - - - -
- salt: string - - - - - - -
-
- - - - - - - - - - -
- cost: number - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<string> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Password } from ".";
-
-
-
-
- - diff --git a/docs/~/Password.hash.html b/docs/~/Password.hash.html deleted file mode 100644 index fc39ca28..00000000 --- a/docs/~/Password.hash.html +++ /dev/null @@ -1,357 +0,0 @@ - - - - Password.hash - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Password.hash -
- - - - -
-
- -

Hash the password using the specified password algorithm

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- password: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
algo: Algorithms = PASSWORD_DEFAULT - -
- - - - -
-
- - - - - - - - - - -
-
optional
-
options: PasswordOptions = DEFAULT_OPTS - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<string> - - - - - - -

Hash string containing algo, cost, salt and hash

-
-
-
-
-
-
-
-
-

Usage

import { Password } from ".";
-
-
-
-
- - diff --git a/docs/~/Password.html b/docs/~/Password.html deleted file mode 100644 index aa2b5122..00000000 --- a/docs/~/Password.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - Password - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Password } from ".";
-
-
-
-
- - diff --git a/docs/~/Password.prototype.html b/docs/~/Password.prototype.html deleted file mode 100644 index acecbf2a..00000000 --- a/docs/~/Password.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Password.verify.html b/docs/~/Password.verify.html deleted file mode 100644 index c0ae855d..00000000 --- a/docs/~/Password.verify.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - Password.verify - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Password.verify -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- password: string - - - - - - -

Input password to check against

-
-
- - - - - - - - - - -
- hash: string - - - - - - -

Hash string input from Password.hash()

-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<boolean> - - - - - - -

Promise Whether the password was valid or not

-
-
-
-
-
-
-
-
-

Usage

import { Password } from ".";
-
-
-
-
- - diff --git a/docs/~/PasswordOptions.allowInsecure.html b/docs/~/PasswordOptions.allowInsecure.html deleted file mode 100644 index d5aebcd5..00000000 --- a/docs/~/PasswordOptions.allowInsecure.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - PasswordOptions.allowInsecure - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { type PasswordOptions } from ".";
-
-
-
-
- - diff --git a/docs/~/PasswordOptions.cost.html b/docs/~/PasswordOptions.cost.html deleted file mode 100644 index ee61eb69..00000000 --- a/docs/~/PasswordOptions.cost.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - PasswordOptions.cost - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { type PasswordOptions } from ".";
-
-
-
-
- - diff --git a/docs/~/PasswordOptions.html b/docs/~/PasswordOptions.html deleted file mode 100644 index 2a72ae0c..00000000 --- a/docs/~/PasswordOptions.html +++ /dev/null @@ -1,210 +0,0 @@ - - - - PasswordOptions - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { type PasswordOptions } from ".";
-
-
-
-
- - diff --git a/docs/~/QueryParameters.html b/docs/~/QueryParameters.html deleted file mode 100644 index bb7b2dc8..00000000 --- a/docs/~/QueryParameters.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - QueryParameters - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { type QueryParameters } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.html b/docs/~/Queue.html deleted file mode 100644 index bacbea62..00000000 --- a/docs/~/Queue.html +++ /dev/null @@ -1,735 +0,0 @@ - - - - Queue - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Queue -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
Queue(scheduler?: Scheduler) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

- - - - - - - - - - -
-
readonly
-
count: number - -
- - - - -

Get the number of items contained in the Queue

-
-
- - - - - - - - - - -
-
readonly
-
dump: QueueItem[] - -
- - - - -

Return all the items in the queue

-
-
- - - - - - - - - - -
-
readonly
-
isEmpty: boolean - -
- - - - -

Check whether the Queue has any items

-
-
- - - - - - - - - - -
-
readonly
-
next: QueueItem | null - -
- - - - -

Get the next item from the queue. -Unlike the Queue#peek() method, this does remove the item.

-
-
- - - - - - - - - - -
-
readonly
-
peek: QueueItem | null - -
- - - - -

Get the next item from the queue. -Unlike the Queue#next() method, this does not remove the item.

-
-
- - - - - - - - - - -
-
private
-
items: QueueItem[] - -
- - - - -
-
- - - - - - - - - - -
-
readonly
-
private
-
scheduler: Scheduler - -
- - - - -
-
-
-
- - - - - - - - - - -
- add(item: QueueItem): void - - - - - - -

Add an item to the queue based on the scheduler used

-
-
- - - - - - - - - - -
- clear(): void - - - - - - -

Remove all items from the Queue

-
-
- - - - - - - - - - -
- contains(item: QueueItem): boolean - - - - - - -

Check whether the queue already contains an identical item

-
-
-
-
-
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.add.html b/docs/~/Queue.prototype.add.html deleted file mode 100644 index 50a91f2b..00000000 --- a/docs/~/Queue.prototype.add.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - Queue.prototype.add - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Queue.prototype.add -
- - - - -
-
- -

Add an item to the queue based on the scheduler used

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- item: QueueItem - - - - - - -

Item to add to the queue

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.clear.html b/docs/~/Queue.prototype.clear.html deleted file mode 100644 index 160ceab8..00000000 --- a/docs/~/Queue.prototype.clear.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - Queue.prototype.clear - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Queue.prototype.clear -
- - - - -
-
- -

Remove all items from the Queue

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- void - - - - - - -

void

-
-
-
-
-
-
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.contains.html b/docs/~/Queue.prototype.contains.html deleted file mode 100644 index 30eb7699..00000000 --- a/docs/~/Queue.prototype.contains.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - Queue.prototype.contains - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Queue.prototype.contains -
- - - - -
-
- -

Check whether the queue already contains an identical item

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- item: QueueItem - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- boolean - - - - - - -

boolean

-
-
-
-
-
-
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.count.html b/docs/~/Queue.prototype.count.html deleted file mode 100644 index aac3f538..00000000 --- a/docs/~/Queue.prototype.count.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - Queue.prototype.count - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Queue.prototype.count -
- - - - -
-
- -

Get the number of items contained in the Queue

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- number - - - - - - -

number

-
-
-
-
-
-
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.dump.html b/docs/~/Queue.prototype.dump.html deleted file mode 100644 index 9d63fa3e..00000000 --- a/docs/~/Queue.prototype.dump.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - Queue.prototype.dump - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Queue.prototype.dump -
- - - - -
-
- -

Return all the items in the queue

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- QueueItem[] - - - - - - -

QueueItems[]

-
-
-
-
-
-
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.html b/docs/~/Queue.prototype.html deleted file mode 100644 index 730bda54..00000000 --- a/docs/~/Queue.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Queue.prototype.isEmpty.html b/docs/~/Queue.prototype.isEmpty.html deleted file mode 100644 index 9d7f13c1..00000000 --- a/docs/~/Queue.prototype.isEmpty.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - Queue.prototype.isEmpty - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Queue.prototype.isEmpty -
- - - - -
-
- -

Check whether the Queue has any items

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- boolean - - - - - - -

boolean

-
-
-
-
-
-
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.items.html b/docs/~/Queue.prototype.items.html deleted file mode 100644 index 79438111..00000000 --- a/docs/~/Queue.prototype.items.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Queue.prototype.items - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.next.html b/docs/~/Queue.prototype.next.html deleted file mode 100644 index 543d679b..00000000 --- a/docs/~/Queue.prototype.next.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - Queue.prototype.next - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Queue.prototype.next -
- - - - -
-
- -

Get the next item from the queue. -Unlike the Queue#peek() method, this does remove the item.

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- QueueItem | null - - - - - - -

QueueItem

-
-
-
-
-
-
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.peek.html b/docs/~/Queue.prototype.peek.html deleted file mode 100644 index 78be8e2d..00000000 --- a/docs/~/Queue.prototype.peek.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - Queue.prototype.peek - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Queue.prototype.peek -
- - - - -
-
- -

Get the next item from the queue. -Unlike the Queue#next() method, this does not remove the item.

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- QueueItem | null - - - - - - -

QueueItem|null

-
-
-
-
-
-
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/Queue.prototype.scheduler.html b/docs/~/Queue.prototype.scheduler.html deleted file mode 100644 index 033afc90..00000000 --- a/docs/~/Queue.prototype.scheduler.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Queue.prototype.scheduler - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Queue } from ".";
-
-
-
-
- - diff --git a/docs/~/RCON.html b/docs/~/RCON.html deleted file mode 100644 index a7cdf0b9..00000000 --- a/docs/~/RCON.html +++ /dev/null @@ -1,445 +0,0 @@ - - - - RCON - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class RCON -
- - - - -
-
-

- - - - - - - - - - -Properties

-
-
- - - - - - - - - - -
- close(): Promise<void> - - - - - - -

Close connection to the server

-
-
- - - - - - - - - - -
- connect(ip: string, port: number, password?: string | null): Promise<void> - - - - - - -

Connect to an RCON server.

-
-
- - - - - - - - - - -
-
private
-
recv(): Promise<string> - -
- - - - -

Create a buffer to receive data from the server

-
-
- - - - - - - - - - -
- send(data: string, cmd?: keyof PacketType): Promise<string> - - - - - - -

Send data to the server

-
-
- - - - - - - - - - -
- sendSync(data: string, cmd?: keyof PacketType): void - - - - - - -

Send data to the server. -It is preferred to use RCON#send instead. -TODO: Return data received from server

-
-
-
-
-
-
-
-

Usage

import { RCON } from ".";
-
-
-
-
- - diff --git a/docs/~/RCON.prototype.close.html b/docs/~/RCON.prototype.close.html deleted file mode 100644 index a8db4acb..00000000 --- a/docs/~/RCON.prototype.close.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - RCON.prototype.close - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method RCON.prototype.close -
- - - - -
-
- -

Close connection to the server

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -

Promise

-
-
-
-
-
-
-
-
-

Usage

import { RCON } from ".";
-
-
-
-
- - diff --git a/docs/~/RCON.prototype.conn.html b/docs/~/RCON.prototype.conn.html deleted file mode 100644 index f79e45df..00000000 --- a/docs/~/RCON.prototype.conn.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - RCON.prototype.conn - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { RCON } from ".";
-
-
-
-
- - diff --git a/docs/~/RCON.prototype.connect.html b/docs/~/RCON.prototype.connect.html deleted file mode 100644 index 50c2015b..00000000 --- a/docs/~/RCON.prototype.connect.html +++ /dev/null @@ -1,356 +0,0 @@ - - - - RCON.prototype.connect - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method RCON.prototype.connect -
- - - - -
-
- -

Connect to an RCON server.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- ip: string - - - - - - -
-
- - - - - - - - - - -
- port: number - - - - - - -
-
- - - - - - - - - - -
-
optional
-
password: string | null = null - -
- - - - -

Optional password for authentication

-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { RCON } from ".";
-
-
-
-
- - diff --git a/docs/~/RCON.prototype.html b/docs/~/RCON.prototype.html deleted file mode 100644 index 093ec3c0..00000000 --- a/docs/~/RCON.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/RCON.prototype.recv.html b/docs/~/RCON.prototype.recv.html deleted file mode 100644 index 1fe99283..00000000 --- a/docs/~/RCON.prototype.recv.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - RCON.prototype.recv - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method RCON.prototype.recv -
- - - - -
-
- -

Create a buffer to receive data from the server

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<string> - - - - - - -

Promise Data received from the server

-
-
-
-
-
-
-
-
-

Usage

import { RCON } from ".";
-
-
-
-
- - diff --git a/docs/~/RCON.prototype.send.html b/docs/~/RCON.prototype.send.html deleted file mode 100644 index 6b160fd6..00000000 --- a/docs/~/RCON.prototype.send.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - RCON.prototype.send - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method RCON.prototype.send -
- - - - -
-
- -

Send data to the server

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- data: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
cmd: keyof PacketType - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<string> - - - - - - -

Promise

-
-
-
-
-
-
-
-
-

Usage

import { RCON } from ".";
-
-
-
-
- - diff --git a/docs/~/RCON.prototype.sendSync.html b/docs/~/RCON.prototype.sendSync.html deleted file mode 100644 index 142d90e2..00000000 --- a/docs/~/RCON.prototype.sendSync.html +++ /dev/null @@ -1,307 +0,0 @@ - - - - RCON.prototype.sendSync - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method RCON.prototype.sendSync -
- - - - -
-
- -

Send data to the server. -It is preferred to use RCON#send instead. -TODO: Return data received from server

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- data: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
cmd: keyof PacketType - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- void - - - - - - -

void

-
-
-
-
-
-
-
-
-

Usage

import { RCON } from ".";
-
-
-
-
- - diff --git a/docs/~/Random.bytes.html b/docs/~/Random.bytes.html deleted file mode 100644 index d079f7d1..00000000 --- a/docs/~/Random.bytes.html +++ /dev/null @@ -1,323 +0,0 @@ - - - - Random.bytes - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Random.bytes -
- - - - -
-
- -

Generate random bytes. -These bytes are generated using the Web Crypto API, this is cryptographically secure.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Random } from "https://deno.land/x/chomp/security/random.ts";
-
-// Generates 16 random bytes
-const bytes = Random.bytes(16);
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- length: number - - - - - - -

Amount of bytes to be generated

-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Uint8Array - - - - - - -

Uint8Array

-
-
-
-
-
-
-
-
-

Usage

import { Random } from ".";
-
-
-
-
- - diff --git a/docs/~/Random.float.html b/docs/~/Random.float.html deleted file mode 100644 index 9249a59f..00000000 --- a/docs/~/Random.float.html +++ /dev/null @@ -1,474 +0,0 @@ - - - - Random.float - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Random.float -
- - - - -
-
- -

Inclusively generate a random float between min and max. -If you do not want to use decimals, please use Random.integer() instead.

-

By default, these floats are NOT cryptographically secure (for performance reasons). -Set the "secure" argument to "true" if you are using this for cryptographic purposes!

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Random } from "https://deno.land/x/chomp/security/random.ts";
-
-// Generate a random float between 0 and 1
-const num = await Random.float(0, 1);
-
-
-
-
-
- - - - - - - - - - -
- -

Cryptographically secure

-
-
import { Random } from "https://deno.land/x/chomp/security/random.ts";
-
-// Generate a secure random float between 0 and 1
-const num = await Random.float(0, 1, true);
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
-
optional
-
min: number = 0 - -
- - - - -

Minimum allowable float

-
-
- - - - - - - - - - -
-
optional
-
max: number = 1 - -
- - - - -

Maximum allowable float

-
-
- - - - - - - - - - -
-
optional
-
secure: boolean = false - -
- - - - -

Using this for cryptographic purposes?

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Random } from ".";
-
-
-
-
- - diff --git a/docs/~/Random.html b/docs/~/Random.html deleted file mode 100644 index 7c77c2bd..00000000 --- a/docs/~/Random.html +++ /dev/null @@ -1,321 +0,0 @@ - - - - Random - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Random -
- - - - -
-
-

- - - - - - - - - - -Static Methods

- - - - - - - - - - -
- bytes(length: number): Uint8Array - - - - - - -

Generate random bytes. -These bytes are generated using the Web Crypto API, this is cryptographically secure.

-
-
- - - - - - - - - - -
- float(min?: number, max?: number, secure?: boolean): number - - - - - - -

Inclusively generate a random float between min and max. -If you do not want to use decimals, please use Random.integer() instead.

-

By default, these floats are NOT cryptographically secure (for performance reasons). -Set the "secure" argument to "true" if you are using this for cryptographic purposes!

-
-
- - - - - - - - - - -
- integer(min?: number, max?: number, secure?: boolean): number - - - - - - -

Inclusively generate a random integer between min and max. -If you want to use decimals, please use "Random.float() | Random.float()" instead.

-

By default, these integers are NOT cryptographically secure (for performance reasons). -Set the "secure" argument to "true" if you are using this for cryptographic purposes!

-
-
- - - - - - - - - - -
- string(length: number): Promise<string> - - - - - - -

Generate a random string. -These strings are generated using the Web Crypto API, this is cryptographically secure.

-
-
-
-
-
-
-
-

Usage

import { Random } from ".";
-
-
-
-
- - diff --git a/docs/~/Random.integer.html b/docs/~/Random.integer.html deleted file mode 100644 index 41b3e687..00000000 --- a/docs/~/Random.integer.html +++ /dev/null @@ -1,474 +0,0 @@ - - - - Random.integer - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Random.integer -
- - - - -
-
- -

Inclusively generate a random integer between min and max. -If you want to use decimals, please use "Random.float() | Random.float()" instead.

-

By default, these integers are NOT cryptographically secure (for performance reasons). -Set the "secure" argument to "true" if you are using this for cryptographic purposes!

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Random } from "https://deno.land/x/chomp/security/random.ts";
-
-// Generate a random integer between 0 and 10
-const num = await Random.integer(0, 10);
-
-
-
-
-
- - - - - - - - - - -
- -

Cryptographically secure

-
-
import { Random } from "https://deno.land/x/chomp/security/random.ts";
-
-// Generate a secure random integer between 0 and 10
-const num = await Random.integer(0, 10, true);
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
-
optional
-
min: number = 0 - -
- - - - -

Minimum allowable integer

-
-
- - - - - - - - - - -
-
optional
-
max: number = 1 - -
- - - - -

Maximum allowable integer

-
-
- - - - - - - - - - -
-
optional
-
secure: boolean = false - -
- - - - -

Using this for cryptographic purposes?

-
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Random } from ".";
-
-
-
-
- - diff --git a/docs/~/Random.prototype.html b/docs/~/Random.prototype.html deleted file mode 100644 index 808ab9b5..00000000 --- a/docs/~/Random.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Random.string.html b/docs/~/Random.string.html deleted file mode 100644 index ccb44fbc..00000000 --- a/docs/~/Random.string.html +++ /dev/null @@ -1,323 +0,0 @@ - - - - Random.string - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Random.string -
- - - - -
-
- -

Generate a random string. -These strings are generated using the Web Crypto API, this is cryptographically secure.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { Random } from "https://deno.land/x/chomp/security/random.ts";
-
-// Generates a string with 16 characters
-const str = await Random.string(16);
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- length: number - - - - - - -

Length of the string to be generated

-
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<string> - - - - - - -

Promise

-
-
-
-
-
-
-
-
-

Usage

import { Random } from ".";
-
-
-
-
- - diff --git a/docs/~/Redis.connect.html b/docs/~/Redis.connect.html deleted file mode 100644 index 776ff13c..00000000 --- a/docs/~/Redis.connect.html +++ /dev/null @@ -1,306 +0,0 @@ - - - - Redis.connect - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Redis.connect -
- - - - -
-
- -

Connect to a Redis node

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
-
optional
-
hostname: string = 127.0.0.1 - -
- - - - -
-
- - - - - - - - - - -
-
optional
-
port: number = 6379 - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -

Promise

-
-
-
-
-
-
-
-
-

Usage

import { Redis } from ".";
-
-
-
-
- - diff --git a/docs/~/Redis.connection.html b/docs/~/Redis.connection.html deleted file mode 100644 index fa5b7956..00000000 --- a/docs/~/Redis.connection.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Redis.connection - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Redis } from ".";
-
-
-
-
- - diff --git a/docs/~/Redis.getConnection.html b/docs/~/Redis.getConnection.html deleted file mode 100644 index 5c4b3d56..00000000 --- a/docs/~/Redis.getConnection.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - Redis.getConnection - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Redis.getConnection -
- - - - -
-
- -

Return the redis connection

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- RedisConn - - - - - - -

any

-
-
-
-
-
-
-
-
-

Usage

import { Redis } from ".";
-
-
-
-
- - diff --git a/docs/~/Redis.html b/docs/~/Redis.html deleted file mode 100644 index b6c97342..00000000 --- a/docs/~/Redis.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - Redis - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Redis } from ".";
-
-
-
-
- - diff --git a/docs/~/Redis.prototype.html b/docs/~/Redis.prototype.html deleted file mode 100644 index 6ea83f53..00000000 --- a/docs/~/Redis.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Request.html b/docs/~/Request.html deleted file mode 100644 index 1c7c7b6c..00000000 --- a/docs/~/Request.html +++ /dev/null @@ -1,743 +0,0 @@ - - - - Request - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Request -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
Request(
url: string
method: string
route: Route
headers: Headers
body: string
auth: string
ip?: string | null
)
-
-
- - - - -
-
-
-
-
-
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getAuth.html b/docs/~/Request.prototype.getAuth.html deleted file mode 100644 index 03d75407..00000000 --- a/docs/~/Request.prototype.getAuth.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Request.prototype.getAuth - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getAuth -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getBody.html b/docs/~/Request.prototype.getBody.html deleted file mode 100644 index 4133c68c..00000000 --- a/docs/~/Request.prototype.getBody.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Request.prototype.getBody - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getBody -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getHeaders.html b/docs/~/Request.prototype.getHeaders.html deleted file mode 100644 index 5f3cb106..00000000 --- a/docs/~/Request.prototype.getHeaders.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Request.prototype.getHeaders - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getHeaders -
- - - - -
-
- - -
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getIp.html b/docs/~/Request.prototype.getIp.html deleted file mode 100644 index ca913265..00000000 --- a/docs/~/Request.prototype.getIp.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Request.prototype.getIp - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getIp -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- string | null - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getMethod.html b/docs/~/Request.prototype.getMethod.html deleted file mode 100644 index aaed7656..00000000 --- a/docs/~/Request.prototype.getMethod.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Request.prototype.getMethod - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getMethod -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getParam.html b/docs/~/Request.prototype.getParam.html deleted file mode 100644 index 64612f01..00000000 --- a/docs/~/Request.prototype.getParam.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Request.prototype.getParam - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getParam -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- name: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- string | null - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getParams.html b/docs/~/Request.prototype.getParams.html deleted file mode 100644 index cd712d84..00000000 --- a/docs/~/Request.prototype.getParams.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Request.prototype.getParams - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getParams -
- - - - -
-
- - -
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getQuery.html b/docs/~/Request.prototype.getQuery.html deleted file mode 100644 index 4b42a987..00000000 --- a/docs/~/Request.prototype.getQuery.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Request.prototype.getQuery - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getQuery -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- name: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- string | null - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getQueryParams.html b/docs/~/Request.prototype.getQueryParams.html deleted file mode 100644 index 60a06237..00000000 --- a/docs/~/Request.prototype.getQueryParams.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Request.prototype.getQueryParams - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getQueryParams -
- - - - -
-
- - -
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getRoute.html b/docs/~/Request.prototype.getRoute.html deleted file mode 100644 index 805a8e00..00000000 --- a/docs/~/Request.prototype.getRoute.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Request.prototype.getRoute - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getRoute -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.getUrl.html b/docs/~/Request.prototype.getUrl.html deleted file mode 100644 index 6dcb9419..00000000 --- a/docs/~/Request.prototype.getUrl.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Request.prototype.getUrl - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Request.prototype.getUrl -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Request } from ".";
-
-
-
-
- - diff --git a/docs/~/Request.prototype.html b/docs/~/Request.prototype.html deleted file mode 100644 index 8508e9d0..00000000 --- a/docs/~/Request.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/RequestParameters.html b/docs/~/RequestParameters.html deleted file mode 100644 index 27ecad0c..00000000 --- a/docs/~/RequestParameters.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - RequestParameters - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { type RequestParameters } from ".";
-
-
-
-
- - diff --git a/docs/~/Router._controllerDir.html b/docs/~/Router._controllerDir.html deleted file mode 100644 index c2b69707..00000000 --- a/docs/~/Router._controllerDir.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Router._controllerDir - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.add.html b/docs/~/Router.add.html deleted file mode 100644 index 6d7f72ac..00000000 --- a/docs/~/Router.add.html +++ /dev/null @@ -1,254 +0,0 @@ - - - - Router.add - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Router.add -
- - - - -
-
- -

Add a route. -Defaults to 'GET'

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- route: Route - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- void - - - - - - -

void

-
-
-
-
-
-
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.execute.html b/docs/~/Router.execute.html deleted file mode 100644 index 4b50214f..00000000 --- a/docs/~/Router.execute.html +++ /dev/null @@ -1,304 +0,0 @@ - - - - Router.execute - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Router.execute -
- - - - -
-
- -

Execute the requested controller action

-
-
-

- - - - - - - - - - -Parameters

-
- - - - - - - - - - -
- clientIp: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<Response> - - - - - - -

Promise<Response|null>

-
-
-
-
-
-
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.getAuth.html b/docs/~/Router.getAuth.html deleted file mode 100644 index 2da8241a..00000000 --- a/docs/~/Router.getAuth.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - Router.getAuth - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Router.getAuth -
- - - - -
-
- -

Check if there is an authorization header set, return it if so

-
-
-

- - - - - - - - - - -Parameters

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- string - - - - - - -

string

-
-
-
-
-
-
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.getBody.html b/docs/~/Router.getBody.html deleted file mode 100644 index bf5a4d56..00000000 --- a/docs/~/Router.getBody.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - Router.getBody - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Router.getBody -
- - - - -
-
- -

Get the body from the request

-
-
-

- - - - - - - - - - -Parameters

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<string> - - - - - - -

Promise

-
-
-
-
-
-
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.getParams.html b/docs/~/Router.getParams.html deleted file mode 100644 index a7520023..00000000 --- a/docs/~/Router.getParams.html +++ /dev/null @@ -1,304 +0,0 @@ - - - - Router.getParams - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Router.getParams -
- - - - -
-
- -

Get the parameters for the given route

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- route: ChompRoute - - - - - - -
-
- - - - - - - - - - -
- path: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -

RequestParameters

-
-
-
-
-
-
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.getQuery.html b/docs/~/Router.getQuery.html deleted file mode 100644 index 372e820e..00000000 --- a/docs/~/Router.getQuery.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - Router.getQuery - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Router.getQuery -
- - - - -
-
- -

Get the query parameters for the given route

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- path: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.getRoutes.html b/docs/~/Router.getRoutes.html deleted file mode 100644 index 4ddd8a99..00000000 --- a/docs/~/Router.getRoutes.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Router.getRoutes - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Router.getRoutes -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.html b/docs/~/Router.html deleted file mode 100644 index 3d9e963d..00000000 --- a/docs/~/Router.html +++ /dev/null @@ -1,651 +0,0 @@ - - - - Router - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Router -
- - - - -
-
-

- - - - - - - - - - -Static Properties

- - - - - - - - - - -
-
private
-
readonly
-
_controllerDir: string - -
- - - - -
-
- - - - - - - - - - -
-
private
-
routes: ChompRoute[] - -
- - - - -
-
-
-
-

- - - - - - - - - - -Static Methods

- - - - - - - - - - -
- add(route: Route): void - - - - - - -

Add a route. -Defaults to 'GET'

-
-
- - - - - - - - - - -
- execute(request: Request, clientIp: string): Promise<Response> - - - - - - -

Execute the requested controller action

-
-
- - - - - - - - - - -
- getAuth(request: Request): string - - - - - - -

Check if there is an authorization header set, return it if so

-
-
- - - - - - - - - - -
- getBody(request: Request): Promise<string> - - - - - - -

Get the body from the request

-
-
- - - - - - - - - - -
- getParams(route: ChompRoute, path: string): RequestParameters - - - - - - -

Get the parameters for the given route

-
-
- - - - - - - - - - -
- getQuery(path: string): QueryParameters - - - - - - -

Get the query parameters for the given route

-
- -
- - - - - - - - - - -
- route(request: Request) - - - - - - -

Match the controller and action to a route

-
-
-
-
-
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.prototype.html b/docs/~/Router.prototype.html deleted file mode 100644 index c08193bf..00000000 --- a/docs/~/Router.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Router.route.html b/docs/~/Router.route.html deleted file mode 100644 index f7677385..00000000 --- a/docs/~/Router.route.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - Router.route - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Router.route -
- - - - -
-
- -

Match the controller and action to a route

-
-
-

- - - - - - - - - - -Parameters

-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/Router.routes.html b/docs/~/Router.routes.html deleted file mode 100644 index 9a7a06ca..00000000 --- a/docs/~/Router.routes.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Router.routes - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Router } from ".";
-
-
-
-
- - diff --git a/docs/~/StatusCodes.html b/docs/~/StatusCodes.html deleted file mode 100644 index 2187c87b..00000000 --- a/docs/~/StatusCodes.html +++ /dev/null @@ -1,3318 +0,0 @@ - - - - StatusCodes - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- enum StatusCodes -
- - - - -
-
- - - - - - - - - - -
- ACCEPTED = 202 - - - - - - -
-
- - - - - - - - - - -
- ALREADY_REPORTED = 208 - - - - - - -
-
- - - - - - - - - - -
- BAD_GATEWAY = 502 - - - - - - -
-
- - - - - - - - - - -
- BAD_REQUEST = 400 - - - - - - -
-
- - - - - - - - - - -
- CONFLICT = 409 - - - - - - -
-
- - - - - - - - - - -
- CONTINUE = 100 - - - - - - -
-
- - - - - - - - - - -
- CREATED = 201 - - - - - - -
-
- - - - - - - - - - -
- EARLY_HINTS = 103 - - - - - - -
-
- - - - - - - - - - -
- EXPECTATION_FAILED = 417 - - - - - - -
-
- - - - - - - - - - -
- FAILED_DEPENDENCY = 424 - - - - - - -
-
- - - - - - - - - - -
- FORBIDDEN = 403 - - - - - - -
-
- - - - - - - - - - -
- FOUND = 302 - - - - - - -
-
- - - - - - - - - - -
- GATEWAY_TIMEOUT = 504 - - - - - - -
-
- - - - - - - - - - -
- GONE = 410 - - - - - - -
-
- - - - - - - - - - -
- HTTP_VERSION_NOT_SUPPORTED = 505 - - - - - - -
-
- - - - - - - - - - -
- IM_A_TEAPOT = 418 - - - - - - -
-
- - - - - - - - - - -
- IM_USED = 226 - - - - - - -
-
- - - - - - - - - - -
- INSUFFICIENT_STORAGE = 507 - - - - - - -
-
- - - - - - - - - - -
- INTERNAL_SERVER_ERROR = 500 - - - - - - -
-
- - - - - - - - - - -
- LENGTH_REQUIRED = 411 - - - - - - -
-
- - - - - - - - - - -
- LOCKED = 423 - - - - - - -
-
- - - - - - - - - - -
- LOOP_DETECTED = 508 - - - - - - -
-
- - - - - - - - - - -
- METHOD_NOT_ALLOWED = 405 - - - - - - -
-
- - - - - - - - - - -
- MISDIRECTED_REQUEST = 421 - - - - - - -
-
- - - - - - - - - - -
- MOVED_PERMANENTLY = 301 - - - - - - -
-
- - - - - - - - - - -
- MULTIPLE_CHOICES = 300 - - - - - - -
-
- - - - - - - - - - -
- MULTI_STATUS = 207 - - - - - - -
-
- - - - - - - - - - -
- NETWORK_AUTHENTICATION_REQUIRED = 511 - - - - - - -
-
- - - - - - - - - - -
- NON_AUTHORATIVE_INFORMATION = 203 - - - - - - -
-
- - - - - - - - - - -
- NOT_ACCEPTABLE = 406 - - - - - - -
-
- - - - - - - - - - -
- NOT_EXTENDED = 510 - - - - - - -
-
- - - - - - - - - - -
- NOT_FOUND = 404 - - - - - - -
-
- - - - - - - - - - -
- NOT_IMPLEMENTED = 501 - - - - - - -
-
- - - - - - - - - - -
- NOT_MODIFIED = 304 - - - - - - -
-
- - - - - - - - - - -
- NO_CONTENT = 204 - - - - - - -
-
- - - - - - - - - - -
- OK = 200 - - - - - - -
-
- - - - - - - - - - -
- PARTIAL_CONTENT = 206 - - - - - - -
-
- - - - - - - - - - -
- PAYLOAD_TOO_LARGE = 413 - - - - - - -
-
- - - - - - - - - - -
- PAYMENT_REQUIRED = 402 - - - - - - -
-
- - - - - - - - - - -
- PERMANENT_REDIRECT = 308 - - - - - - -
-
- - - - - - - - - - -
- PRECONDITION_FAILED = 412 - - - - - - -
-
- - - - - - - - - - -
- PRECONDITION_REQUIRED = 428 - - - - - - -
-
- - - - - - - - - - -
- PROCESSING = 102 - - - - - - -
-
- - - - - - - - - - -
- PROXY_AUTHENTICATION_REQUIRED = 407 - - - - - - -
-
- - - - - - - - - - -
- RANGE_NOT_SATISFIABLE = 416 - - - - - - -
-
- - - - - - - - - - -
- REQUEST_HEADER_FIELDS_TOO_LARGE = 431 - - - - - - -
-
- - - - - - - - - - -
- REQUEST_TIMEOUT = 408 - - - - - - -
-
- - - - - - - - - - -
- RESET_CONTENT = 205 - - - - - - -
-
- - - - - - - - - - -
- SEE_OTHER = 303 - - - - - - -
-
- - - - - - - - - - -
- SERVICE_UNAVAILABLE = 503 - - - - - - -
-
- - - - - - - - - - -
- SWITCHING_PROTOCOLS = 101 - - - - - - -
-
- - - - - - - - - - -
- TEMPORARY_REDIRECT = 307 - - - - - - -
-
- - - - - - - - - - -
- TOO_EARLY = 425 - - - - - - -
-
- - - - - - - - - - -
- TOO_MANY_REQUESTS = 429 - - - - - - -
-
- - - - - - - - - - -
- UNAUTHORIZED = 401 - - - - - - -
- -
- - - - - - - - - - -
- UNPROCESSABLE_CONTENT = 422 - - - - - - -
-
- - - - - - - - - - -
- UNSUPPORTED_MEDIA_TYPE = 415 - - - - - - -
-
- - - - - - - - - - -
- UNUSED = 306 - - - - - - -
-
- - - - - - - - - - -
- UPGRADE_REQUIRED = 426 - - - - - - -
-
- - - - - - - - - - -
- URI_TOO_LONG = 414 - - - - - - -
-
- - - - - - - - - - -
- USE_PROXY = 305 - - - - - - -
-
- - - - - - - - - - -
- VARIANT_ALSO_NEGOTIATED = 506 - - - - - - -
-
-
-
-
-
-
-

Usage

import { StatusCodes } from ".";
-
-
-
-
- - diff --git a/docs/~/Text.html b/docs/~/Text.html deleted file mode 100644 index fa65b36c..00000000 --- a/docs/~/Text.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - Text - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Text } from ".";
-
-
-
-
- - diff --git a/docs/~/Text.htmlentities.html b/docs/~/Text.htmlentities.html deleted file mode 100644 index 5681769f..00000000 --- a/docs/~/Text.htmlentities.html +++ /dev/null @@ -1,254 +0,0 @@ - - - - Text.htmlentities - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Text.htmlentities -
- - - - -
-
- -

Replace special characters with their HTML entities. -TODO: Add support for diacritical marks.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- str: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- string - - - - - - -

string

-
-
-
-
-
-
-
-
-

Usage

import { Text } from ".";
-
-
-
-
- - diff --git a/docs/~/Text.prototype.html b/docs/~/Text.prototype.html deleted file mode 100644 index d8411d2f..00000000 --- a/docs/~/Text.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Text.tokenize.html b/docs/~/Text.tokenize.html deleted file mode 100644 index 87980b82..00000000 --- a/docs/~/Text.tokenize.html +++ /dev/null @@ -1,304 +0,0 @@ - - - - Text.tokenize - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Text.tokenize -
- - - - -
-
- -

Tokenize a string into an array of strings.

-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- input: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
limit: number = 3 - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- string[] - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Text } from ".";
-
-
-
-
- - diff --git a/docs/~/Text.uuid.html b/docs/~/Text.uuid.html deleted file mode 100644 index b515f916..00000000 --- a/docs/~/Text.uuid.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - Text.uuid - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Text.uuid -
- - - - -
-
- -

Generate unique identifiers as per RFC-4122.

-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-
-

Usage

import { Text } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.html b/docs/~/Time.html deleted file mode 100644 index 040d9b32..00000000 --- a/docs/~/Time.html +++ /dev/null @@ -1,983 +0,0 @@ - - - - Time - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Time -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
Time(time?: string | undefined) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

- - - - - - - - -
- - - - - - - - - - -
-
readonly
-
private
-
time - -
- - - - -
-
-
-
- - - - - - - - - - -
- add(input: string) - - - - - - -
-
- - - - - - - - - - -
- addDay(days?: number) - - - - - - -
-
- - - - - - - - - - -
- addWeek(weeks?: number) - - - - - - -
-
- - - - - - - - - - -
- format(format: string) - - - - - - -
- -
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.add.html b/docs/~/Time.prototype.add.html deleted file mode 100644 index a6cc3a1b..00000000 --- a/docs/~/Time.prototype.add.html +++ /dev/null @@ -1,200 +0,0 @@ - - - - Time.prototype.add - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.add -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- input: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.addDay.html b/docs/~/Time.prototype.addDay.html deleted file mode 100644 index b6047f84..00000000 --- a/docs/~/Time.prototype.addDay.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - Time.prototype.addDay - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.addDay -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
-
optional
-
days: number = 1 - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.addWeek.html b/docs/~/Time.prototype.addWeek.html deleted file mode 100644 index 360b15bf..00000000 --- a/docs/~/Time.prototype.addWeek.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - Time.prototype.addWeek - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.addWeek -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
-
optional
-
weeks: number = 1 - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.format.html b/docs/~/Time.prototype.format.html deleted file mode 100644 index 3a6a6a10..00000000 --- a/docs/~/Time.prototype.format.html +++ /dev/null @@ -1,200 +0,0 @@ - - - - Time.prototype.format - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.format -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- format: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.getTime.html b/docs/~/Time.prototype.getTime.html deleted file mode 100644 index c70cda39..00000000 --- a/docs/~/Time.prototype.getTime.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.getTime - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.getTime -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.hours.html b/docs/~/Time.prototype.hours.html deleted file mode 100644 index 158a1edc..00000000 --- a/docs/~/Time.prototype.hours.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.hours - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.hours -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.html b/docs/~/Time.prototype.html deleted file mode 100644 index 6878fb68..00000000 --- a/docs/~/Time.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Time.prototype.midnight.html b/docs/~/Time.prototype.midnight.html deleted file mode 100644 index 8ae5789e..00000000 --- a/docs/~/Time.prototype.midnight.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.midnight - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.midnight -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.milliseconds.html b/docs/~/Time.prototype.milliseconds.html deleted file mode 100644 index 65c826c0..00000000 --- a/docs/~/Time.prototype.milliseconds.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.milliseconds - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.milliseconds -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.minutes.html b/docs/~/Time.prototype.minutes.html deleted file mode 100644 index 35bf58f5..00000000 --- a/docs/~/Time.prototype.minutes.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.minutes - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.minutes -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.month.html b/docs/~/Time.prototype.month.html deleted file mode 100644 index 3266de75..00000000 --- a/docs/~/Time.prototype.month.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.month - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.month -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.monthDay.html b/docs/~/Time.prototype.monthDay.html deleted file mode 100644 index 5786e116..00000000 --- a/docs/~/Time.prototype.monthDay.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.monthDay - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.monthDay -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.seconds.html b/docs/~/Time.prototype.seconds.html deleted file mode 100644 index baddd57b..00000000 --- a/docs/~/Time.prototype.seconds.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.seconds - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.seconds -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.time.html b/docs/~/Time.prototype.time.html deleted file mode 100644 index 754bfd10..00000000 --- a/docs/~/Time.prototype.time.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - Time.prototype.time - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- property Time.prototype.time -
- - - - -
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.weekDay.html b/docs/~/Time.prototype.weekDay.html deleted file mode 100644 index df4634ed..00000000 --- a/docs/~/Time.prototype.weekDay.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.weekDay - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.weekDay -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/Time.prototype.year.html b/docs/~/Time.prototype.year.html deleted file mode 100644 index a370f7ae..00000000 --- a/docs/~/Time.prototype.year.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Time.prototype.year - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Time.prototype.year -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Time } from ".";
-
-
-
-
- - diff --git a/docs/~/TimeString.html b/docs/~/TimeString.html deleted file mode 100644 index d9ed30e7..00000000 --- a/docs/~/TimeString.html +++ /dev/null @@ -1,370 +0,0 @@ - - - - TimeString - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- function TimeString -
- - - - -
-
- -

Takes a time string and turns it into milliseconds

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { TimeStringSeconds } from "https://deno.land/x/chomp/utility/time-string.ts";
-
-const milliseconds = TimeString`+1 minute`;
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- strIn: TemplateStringsArray - - - - - - -
-
- - - - - - - - - - -
- ...parts: any[] - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- number - - - - - - -

number

-
-
-
-
-
-
-
-
-

Usage

import { TimeString } from ".";
-
-
-
-
- - diff --git a/docs/~/TimeStringSeconds.html b/docs/~/TimeStringSeconds.html deleted file mode 100644 index 3c00a4e5..00000000 --- a/docs/~/TimeStringSeconds.html +++ /dev/null @@ -1,370 +0,0 @@ - - - - TimeStringSeconds - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- function TimeStringSeconds -
- - - - -
-
- -

Takes a time string and turns it into round seconds

-
-
- - - - - - - - - - -
- -

Example 1

-
-
import { TimeStringSeconds } from "https://deno.land/x/chomp/utility/time-string.ts";
-
-const seconds = TimeStringSeconds`+1 minute`;
-
-
-
-
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- strIn: TemplateStringsArray - - - - - - -
-
- - - - - - - - - - -
- ...parts: any[] - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- number - - - - - - -

number

-
-
-
-
-
-
-
-
-

Usage

import { TimeStringSeconds } from ".";
-
-
-
-
- - diff --git a/docs/~/ViewVariable.html b/docs/~/ViewVariable.html deleted file mode 100644 index fbd1eef1..00000000 --- a/docs/~/ViewVariable.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - ViewVariable - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { type ViewVariable } from ".";
-
-
-
-
- - diff --git a/docs/~/Webserver.html b/docs/~/Webserver.html deleted file mode 100644 index 29efbae9..00000000 --- a/docs/~/Webserver.html +++ /dev/null @@ -1,362 +0,0 @@ - - - - Webserver - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Webserver } from ".";
-
-
-
-
- - diff --git a/docs/~/Webserver.prototype.html b/docs/~/Webserver.prototype.html deleted file mode 100644 index 47cfedd7..00000000 --- a/docs/~/Webserver.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Webserver.prototype.serve.html b/docs/~/Webserver.prototype.serve.html deleted file mode 100644 index 6fe41a14..00000000 --- a/docs/~/Webserver.prototype.serve.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Webserver.prototype.serve - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Webserver.prototype.serve -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Webserver } from ".";
-
-
-
-
- - diff --git a/docs/~/Webserver.prototype.server.html b/docs/~/Webserver.prototype.server.html deleted file mode 100644 index d72c9ca2..00000000 --- a/docs/~/Webserver.prototype.server.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Webserver.prototype.server - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Webserver } from ".";
-
-
-
-
- - diff --git a/docs/~/Webserver.prototype.start.html b/docs/~/Webserver.prototype.start.html deleted file mode 100644 index 408a9ea1..00000000 --- a/docs/~/Webserver.prototype.start.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Webserver.prototype.start - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Webserver.prototype.start -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Webserver } from ".";
-
-
-
-
- - diff --git a/docs/~/Websocket.html b/docs/~/Websocket.html deleted file mode 100644 index e6558519..00000000 --- a/docs/~/Websocket.html +++ /dev/null @@ -1,571 +0,0 @@ - - - - Websocket - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- class Websocket -
- - - - -
-
-

- - - - - - - - - - -Constructors

- - - - - - - - - - -
-
new
-
Websocket(port?: number, authenticate?: boolean) - -
- - - - -
-
-
-
-

- - - - - - - - - - -Properties

- - - - - - - - - - -
-
readonly
-
private
-
authenticate: boolean - -
- - - - -
-
- - - - - - - - - - -
-
readonly
-
private
-
port: number - -
- - - - -
-
- - - - - - - - - - -
-
private
-
server: WebSocketServer | null - -
- - - - -
-
-
-
- - - - - - - - - - -
- broadcast(eventString: string, data: any): void - - - - - - -
-
- - - - - - - - - - -
-
private
-
handleEvent(event: string, data?: any) - -
- - - - -
-
- - - - - - - - - - -
-
private
-
onMessage(message: string): Promise<void> - -
- - - - -
- -
-
-
-
-
-
-

Usage

import { Websocket } from ".";
-
-
-
-
- - diff --git a/docs/~/Websocket.prototype.authenticate.html b/docs/~/Websocket.prototype.authenticate.html deleted file mode 100644 index 60076667..00000000 --- a/docs/~/Websocket.prototype.authenticate.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Websocket.prototype.authenticate - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Websocket } from ".";
-
-
-
-
- - diff --git a/docs/~/Websocket.prototype.broadcast.html b/docs/~/Websocket.prototype.broadcast.html deleted file mode 100644 index 1a8fecab..00000000 --- a/docs/~/Websocket.prototype.broadcast.html +++ /dev/null @@ -1,302 +0,0 @@ - - - - Websocket.prototype.broadcast - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Websocket.prototype.broadcast -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- eventString: string - - - - - - -
-
- - - - - - - - - - -
- data: any - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Websocket } from ".";
-
-
-
-
- - diff --git a/docs/~/Websocket.prototype.handleEvent.html b/docs/~/Websocket.prototype.handleEvent.html deleted file mode 100644 index c7f446e9..00000000 --- a/docs/~/Websocket.prototype.handleEvent.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - Websocket.prototype.handleEvent - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Websocket.prototype.handleEvent -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- event: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
data: any = [UNSUPPORTED] - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Websocket } from ".";
-
-
-
-
- - diff --git a/docs/~/Websocket.prototype.html b/docs/~/Websocket.prototype.html deleted file mode 100644 index 9051e529..00000000 --- a/docs/~/Websocket.prototype.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/~/Websocket.prototype.onMessage.html b/docs/~/Websocket.prototype.onMessage.html deleted file mode 100644 index 24d59ca0..00000000 --- a/docs/~/Websocket.prototype.onMessage.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - Websocket.prototype.onMessage - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Websocket.prototype.onMessage -
- - - - -
-
- -
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- message: string - - - - - - -
-
-
-
-

- - - - - - - - - - -Return Type

- - - - - - - - - - -
- Promise<void> - - - - - - -
-
-
-
-
-
-
-
-

Usage

import { Websocket } from ".";
-
-
-
-
- - diff --git a/docs/~/Websocket.prototype.port.html b/docs/~/Websocket.prototype.port.html deleted file mode 100644 index 9506096b..00000000 --- a/docs/~/Websocket.prototype.port.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Websocket.prototype.port - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Websocket } from ".";
-
-
-
-
- - diff --git a/docs/~/Websocket.prototype.server.html b/docs/~/Websocket.prototype.server.html deleted file mode 100644 index c2cc2705..00000000 --- a/docs/~/Websocket.prototype.server.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - Websocket.prototype.server - Chomp documentation - - - - - - - - - - - - - -
-
-
-

Usage

import { Websocket } from ".";
-
-
-
-
- - diff --git a/docs/~/Websocket.prototype.start.html b/docs/~/Websocket.prototype.start.html deleted file mode 100644 index ab6f8d43..00000000 --- a/docs/~/Websocket.prototype.start.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Websocket.prototype.start - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- method Websocket.prototype.start -
- - - - -
-
- -
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { Websocket } from ".";
-
-
-
-
- - diff --git a/docs/~/raise.html b/docs/~/raise.html deleted file mode 100644 index ae10aee3..00000000 --- a/docs/~/raise.html +++ /dev/null @@ -1,547 +0,0 @@ - - - - raise - Chomp documentation - - - - - - - - - - - - - -
-
-
-
- function raise -
- - - - -
-
- -

Utility function that throws an error. -Band-aid for JS not supporting throwing in null-coalescing.

-
-
- - - - - - - - - - -
- -

Basic Usage

-
-
import { raise } from "https://deno.land/x/chomp/error/raise.ts";
-
-const myVar = null ?? raise('Error Message');
-
-
-
-
-
- - - - - - - - - - -
- -

Custom Error types

-
-
import { raise } from "https://deno.land/x/chomp/error/raise.ts";
-
-const myVar = null ?? raise('Error Message', 'CustomError');
-
-// Will automatically append "Error" to the name
-const myVar = null ?? raise('Error Message', 'Custom');
-
-
-
-
-
- - - - - - - - - - -
- -

Custom Error (using Error-classes)

-
-
import { raise } from "https://deno.land/x/chomp/error/raise.ts";
-
-class CustomError extends Error {
-  constructor(public message: string) {
-    super(message);
-  }
-}
-
-const myVar = null ?? raise('Error Message', CustomError);
-
-
-
-
-
-
-
-

- - - - - - - - - - -Type Parameters

- - - - - - - - - - -
- CustomError extends Error - - - - - - -
-
-
-
-

- - - - - - - - - - -Parameters

- - - - - - - - - - -
- err: string - - - - - - -
-
- - - - - - - - - - -
-
optional
-
type: string | (new (err: string) => CustomError) | "Error" = Error - -
- - - - -
-
-
-
-

- - - - - - - - - - -Return Type

-
-
-
-
-
-
-

Usage

import { raise } from ".";
-
-
-
-
- - From 22fa1f8ce0cb2178cf4cf5d3b0807eb226325321 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 23:07:38 +0100 Subject: [PATCH 353/379] Update some docs --- communication/couchdb.ts | 3 +++ communication/uptime-kuma.ts | 3 +++ utility/text.ts | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/communication/couchdb.ts b/communication/couchdb.ts index 0149ad22..43193bda 100644 --- a/communication/couchdb.ts +++ b/communication/couchdb.ts @@ -2,6 +2,9 @@ import { Auth, CouchResponse, CouchRequest, CachedResponse, CouchOverrides} from import { Cache } from "../core/cache.ts"; import { Configure } from "../core/configure.ts"; +/** + * Default cache time + */ const CACHE_TIME = '+1 hour'; /** diff --git a/communication/uptime-kuma.ts b/communication/uptime-kuma.ts index 08854275..7f09d40c 100644 --- a/communication/uptime-kuma.ts +++ b/communication/uptime-kuma.ts @@ -2,6 +2,9 @@ import { UptimeKumaInstance } from "../types/uptime-kuma.ts"; import {fetchWithTimeout} from "../utility/fetch-with-timeout.ts"; import {raise} from "../mod.ts"; +/** + * Interact with an Uptime Kuma instance. + */ export class UptimeKuma { private readonly _host: string = 'http://localhost:3001'; private readonly _id: string; diff --git a/utility/text.ts b/utility/text.ts index 7545d419..61f843db 100644 --- a/utility/text.ts +++ b/utility/text.ts @@ -25,7 +25,8 @@ export class Text { /** * Replace special characters with their HTML entities. - * TODO: Add support for diacritical marks. + * + * @todo Add support for diacritical marks. * * @param str * @returns string From 40910b0f11385d5284544278b69ab13d6866449c Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 23:13:59 +0100 Subject: [PATCH 354/379] Update some validation rules --- validation/rules/is-empty.ts | 13 +++++-------- validation/rules/max-length.ts | 10 +++++++++- validation/rules/min-length.ts | 10 +++++++++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/validation/rules/is-empty.ts b/validation/rules/is-empty.ts index c11db617..2d20de50 100644 --- a/validation/rules/is-empty.ts +++ b/validation/rules/is-empty.ts @@ -1,14 +1,11 @@ import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; +import {empty} from "../../mod.ts"; export function isEmpty(input: any, options: ValidationOptions): ValidationCallbackResponse { - // Check if empty string - if(input === "") return [options.message]; - - // Check if empty array - if(Array.isArray(input) && input.length === 0) return [options.message]; - - // Check if empty object - if(typeof input === "object" && Object.keys(input).length === 0) return [options.message]; + // Check if input is empty + // If so, return the message + const inputIsEmpty = empty(input); + if(inputIsEmpty) return [options.message]; // We have something inside return [undefined]; diff --git a/validation/rules/max-length.ts b/validation/rules/max-length.ts index f9561d87..ce5063ba 100644 --- a/validation/rules/max-length.ts +++ b/validation/rules/max-length.ts @@ -2,6 +2,14 @@ import {ValidationCallbackResponse, ValidationOptions} from "../../types/validat import {valueOrDefault} from "../../utility/value-or-default.ts"; export function maxLength(input: any, options: ValidationOptions): ValidationCallbackResponse { - if(input.length < valueOrDefault(options.parameters?.length, 0)) return [undefined]; + // Get the max length + // If not set, default to 0 + const max = valueOrDefault(options.parameters?.length, 0); + + // Check if we are below the maximum length + const maxLengthExceeded = input.length > max; + if(maxLengthExceeded) return [undefined]; + + // Max length was exceeded return [options.message]; } diff --git a/validation/rules/min-length.ts b/validation/rules/min-length.ts index 0fd57f24..f8db33bc 100644 --- a/validation/rules/min-length.ts +++ b/validation/rules/min-length.ts @@ -2,6 +2,14 @@ import {ValidationCallbackResponse, ValidationOptions} from "../../types/validat import {valueOrDefault} from "../../utility/value-or-default.ts"; export function minLength(input: any, options: ValidationOptions): ValidationCallbackResponse { - if(input.length >= valueOrDefault(options.parameters?.length, 0)) return [undefined]; + // Check if a minimum length was specified + // If not, default to 0 + const min = valueOrDefault(options.parameters?.length, 0); + + // Check if we are above the minimum length + const minLengthReached = input.length >= min; + if(minLengthReached) return [undefined]; + + // Minimum length was not reached return [options.message]; } From 62c122bb18439e1babc8adccfa7546ea6faafcb2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 23:21:16 +0100 Subject: [PATCH 355/379] Rename directory to more line up with current structure --- tests/{util => utility}/contract.test.ts | 0 tests/{util => utility}/error-or-data.test.ts | 0 tests/{util => utility}/inflector.test.ts | 0 tests/{util => utility}/name-of.test.ts | 0 tests/{util => utility}/text.test.ts | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename tests/{util => utility}/contract.test.ts (100%) rename tests/{util => utility}/error-or-data.test.ts (100%) rename tests/{util => utility}/inflector.test.ts (100%) rename tests/{util => utility}/name-of.test.ts (100%) rename tests/{util => utility}/text.test.ts (100%) diff --git a/tests/util/contract.test.ts b/tests/utility/contract.test.ts similarity index 100% rename from tests/util/contract.test.ts rename to tests/utility/contract.test.ts diff --git a/tests/util/error-or-data.test.ts b/tests/utility/error-or-data.test.ts similarity index 100% rename from tests/util/error-or-data.test.ts rename to tests/utility/error-or-data.test.ts diff --git a/tests/util/inflector.test.ts b/tests/utility/inflector.test.ts similarity index 100% rename from tests/util/inflector.test.ts rename to tests/utility/inflector.test.ts diff --git a/tests/util/name-of.test.ts b/tests/utility/name-of.test.ts similarity index 100% rename from tests/util/name-of.test.ts rename to tests/utility/name-of.test.ts diff --git a/tests/util/text.test.ts b/tests/utility/text.test.ts similarity index 100% rename from tests/util/text.test.ts rename to tests/utility/text.test.ts From 0474ed5ed1ca79bf080fedacaab0763af4c57996 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 23:30:58 +0100 Subject: [PATCH 356/379] Move folders around --- {communication => src/communication}/couchdb.ts | 2 +- {communication => src/communication}/druid.ts | 0 {communication => src/communication}/graphql.ts | 0 {communication => src/communication}/influxdb.ts | 0 {communication => src/communication}/loki.ts | 0 {communication => src/communication}/ntfy.ts | 0 {communication => src/communication}/nut.ts | 0 {communication => src/communication}/rcon.ts | 0 {communication => src/communication}/redis.ts | 0 {communication => src/communication}/uptime-kuma.ts | 0 {core => src/core}/cache.ts | 0 {core => src/core}/configure.ts | 0 {core => src/core}/logger.ts | 0 {core => src/core}/mod.ts | 0 {error => src/error}/error-codes.ts | 0 {error => src/error}/raise.ts | 0 {extensions => src/extensions}/array/includes-any.ts | 0 {extensions => src/extensions}/bigint/to-json.ts | 0 {extensions => src/extensions}/date/is-after-or-equal.ts | 0 {extensions => src/extensions}/date/is-after.ts | 0 {extensions => src/extensions}/date/is-before-or-equal.ts | 0 {extensions => src/extensions}/date/is-before.ts | 0 {extensions => src/extensions}/date/set-midnight.ts | 0 {extensions => src/extensions}/string/empty.ts | 0 {filesystem => src/filesystem}/file.ts | 0 {filesystem => src/filesystem}/folder.ts | 0 {queue => src/queue}/queue.ts | 0 {queue => src/queue}/scheduler/first-in-first-out.ts | 0 {queue => src/queue}/scheduler/last-in-first-out.ts | 0 {queue => src/queue}/scheduler/weighted-first-in-first-out.ts | 0 {security => src/security}/hash.ts | 0 {security => src/security}/password.ts | 0 {security => src/security}/random.ts | 0 {utility => src/utility}/check-source.ts | 0 {utility => src/utility}/contract.ts | 0 {utility => src/utility}/cron.ts | 0 {utility => src/utility}/empty.ts | 0 {utility => src/utility}/error-or-data.ts | 0 {utility => src/utility}/fetch-with-timeout.ts | 0 {utility => src/utility}/format-bytes.ts | 0 {utility => src/utility}/inflector.ts | 0 {utility => src/utility}/name-of.ts | 0 {utility => src/utility}/parse-arguments.ts | 0 {utility => src/utility}/registry.ts | 0 {utility => src/utility}/sleep.ts | 0 {utility => src/utility}/text.ts | 0 {utility => src/utility}/time-string.ts | 0 {utility => src/utility}/time.ts | 0 {utility => src/utility}/value-or-default.ts | 0 {validation => src/validation}/rules.ts | 0 {validation => src/validation}/rules/is-empty.ts | 0 {validation => src/validation}/rules/is-null.ts | 0 {validation => src/validation}/rules/is-undefined.ts | 0 {validation => src/validation}/rules/max-length.ts | 0 {validation => src/validation}/rules/min-length.ts | 0 {validation => src/validation}/validator.ts | 0 {webserver => src/webserver}/controller/component.ts | 0 {webserver => src/webserver}/controller/controller.ts | 0 {webserver => src/webserver}/controller/mod.ts | 0 {webserver => src/webserver}/http/mod.ts | 0 {webserver => src/webserver}/http/request.ts | 0 {webserver => src/webserver}/http/response-builder.ts | 0 {webserver => src/webserver}/http/status-codes.ts | 0 {webserver => src/webserver}/mod.ts | 0 {webserver => src/webserver}/pathToRegexp.ts | 0 {webserver => src/webserver}/registry/registry.ts | 0 {webserver => src/webserver}/renderers/handlebars.ts | 0 {webserver => src/webserver}/renderers/json.ts | 0 {webserver => src/webserver}/renderers/mod.ts | 0 {webserver => src/webserver}/renderers/octet-stream.ts | 0 {webserver => src/webserver}/renderers/plaintext.ts | 0 {webserver => src/webserver}/routing/mod.ts | 0 {webserver => src/webserver}/routing/route.ts | 0 {webserver => src/webserver}/routing/router.ts | 0 {webserver => src/webserver}/webserver.ts | 0 {websocket => src/websocket}/authenticator.ts | 0 {websocket => src/websocket}/events.ts | 0 {websocket => src/websocket}/mod.ts | 0 {websocket => src/websocket}/websocket.ts | 0 79 files changed, 1 insertion(+), 1 deletion(-) rename {communication => src/communication}/couchdb.ts (99%) rename {communication => src/communication}/druid.ts (100%) rename {communication => src/communication}/graphql.ts (100%) rename {communication => src/communication}/influxdb.ts (100%) rename {communication => src/communication}/loki.ts (100%) rename {communication => src/communication}/ntfy.ts (100%) rename {communication => src/communication}/nut.ts (100%) rename {communication => src/communication}/rcon.ts (100%) rename {communication => src/communication}/redis.ts (100%) rename {communication => src/communication}/uptime-kuma.ts (100%) rename {core => src/core}/cache.ts (100%) rename {core => src/core}/configure.ts (100%) rename {core => src/core}/logger.ts (100%) rename {core => src/core}/mod.ts (100%) rename {error => src/error}/error-codes.ts (100%) rename {error => src/error}/raise.ts (100%) rename {extensions => src/extensions}/array/includes-any.ts (100%) rename {extensions => src/extensions}/bigint/to-json.ts (100%) rename {extensions => src/extensions}/date/is-after-or-equal.ts (100%) rename {extensions => src/extensions}/date/is-after.ts (100%) rename {extensions => src/extensions}/date/is-before-or-equal.ts (100%) rename {extensions => src/extensions}/date/is-before.ts (100%) rename {extensions => src/extensions}/date/set-midnight.ts (100%) rename {extensions => src/extensions}/string/empty.ts (100%) rename {filesystem => src/filesystem}/file.ts (100%) rename {filesystem => src/filesystem}/folder.ts (100%) rename {queue => src/queue}/queue.ts (100%) rename {queue => src/queue}/scheduler/first-in-first-out.ts (100%) rename {queue => src/queue}/scheduler/last-in-first-out.ts (100%) rename {queue => src/queue}/scheduler/weighted-first-in-first-out.ts (100%) rename {security => src/security}/hash.ts (100%) rename {security => src/security}/password.ts (100%) rename {security => src/security}/random.ts (100%) rename {utility => src/utility}/check-source.ts (100%) rename {utility => src/utility}/contract.ts (100%) rename {utility => src/utility}/cron.ts (100%) rename {utility => src/utility}/empty.ts (100%) rename {utility => src/utility}/error-or-data.ts (100%) rename {utility => src/utility}/fetch-with-timeout.ts (100%) rename {utility => src/utility}/format-bytes.ts (100%) rename {utility => src/utility}/inflector.ts (100%) rename {utility => src/utility}/name-of.ts (100%) rename {utility => src/utility}/parse-arguments.ts (100%) rename {utility => src/utility}/registry.ts (100%) rename {utility => src/utility}/sleep.ts (100%) rename {utility => src/utility}/text.ts (100%) rename {utility => src/utility}/time-string.ts (100%) rename {utility => src/utility}/time.ts (100%) rename {utility => src/utility}/value-or-default.ts (100%) rename {validation => src/validation}/rules.ts (100%) rename {validation => src/validation}/rules/is-empty.ts (100%) rename {validation => src/validation}/rules/is-null.ts (100%) rename {validation => src/validation}/rules/is-undefined.ts (100%) rename {validation => src/validation}/rules/max-length.ts (100%) rename {validation => src/validation}/rules/min-length.ts (100%) rename {validation => src/validation}/validator.ts (100%) rename {webserver => src/webserver}/controller/component.ts (100%) rename {webserver => src/webserver}/controller/controller.ts (100%) rename {webserver => src/webserver}/controller/mod.ts (100%) rename {webserver => src/webserver}/http/mod.ts (100%) rename {webserver => src/webserver}/http/request.ts (100%) rename {webserver => src/webserver}/http/response-builder.ts (100%) rename {webserver => src/webserver}/http/status-codes.ts (100%) rename {webserver => src/webserver}/mod.ts (100%) rename {webserver => src/webserver}/pathToRegexp.ts (100%) rename {webserver => src/webserver}/registry/registry.ts (100%) rename {webserver => src/webserver}/renderers/handlebars.ts (100%) rename {webserver => src/webserver}/renderers/json.ts (100%) rename {webserver => src/webserver}/renderers/mod.ts (100%) rename {webserver => src/webserver}/renderers/octet-stream.ts (100%) rename {webserver => src/webserver}/renderers/plaintext.ts (100%) rename {webserver => src/webserver}/routing/mod.ts (100%) rename {webserver => src/webserver}/routing/route.ts (100%) rename {webserver => src/webserver}/routing/router.ts (100%) rename {webserver => src/webserver}/webserver.ts (100%) rename {websocket => src/websocket}/authenticator.ts (100%) rename {websocket => src/websocket}/events.ts (100%) rename {websocket => src/websocket}/mod.ts (100%) rename {websocket => src/websocket}/websocket.ts (100%) diff --git a/communication/couchdb.ts b/src/communication/couchdb.ts similarity index 99% rename from communication/couchdb.ts rename to src/communication/couchdb.ts index 43193bda..7ca944ea 100644 --- a/communication/couchdb.ts +++ b/src/communication/couchdb.ts @@ -1,4 +1,4 @@ -import { Auth, CouchResponse, CouchRequest, CachedResponse, CouchOverrides} from "../types/couchdb.ts"; +import { Auth, CouchResponse, CouchRequest, CachedResponse, CouchOverrides} from "../@types/couchdb.ts"; import { Cache } from "../core/cache.ts"; import { Configure } from "../core/configure.ts"; diff --git a/communication/druid.ts b/src/communication/druid.ts similarity index 100% rename from communication/druid.ts rename to src/communication/druid.ts diff --git a/communication/graphql.ts b/src/communication/graphql.ts similarity index 100% rename from communication/graphql.ts rename to src/communication/graphql.ts diff --git a/communication/influxdb.ts b/src/communication/influxdb.ts similarity index 100% rename from communication/influxdb.ts rename to src/communication/influxdb.ts diff --git a/communication/loki.ts b/src/communication/loki.ts similarity index 100% rename from communication/loki.ts rename to src/communication/loki.ts diff --git a/communication/ntfy.ts b/src/communication/ntfy.ts similarity index 100% rename from communication/ntfy.ts rename to src/communication/ntfy.ts diff --git a/communication/nut.ts b/src/communication/nut.ts similarity index 100% rename from communication/nut.ts rename to src/communication/nut.ts diff --git a/communication/rcon.ts b/src/communication/rcon.ts similarity index 100% rename from communication/rcon.ts rename to src/communication/rcon.ts diff --git a/communication/redis.ts b/src/communication/redis.ts similarity index 100% rename from communication/redis.ts rename to src/communication/redis.ts diff --git a/communication/uptime-kuma.ts b/src/communication/uptime-kuma.ts similarity index 100% rename from communication/uptime-kuma.ts rename to src/communication/uptime-kuma.ts diff --git a/core/cache.ts b/src/core/cache.ts similarity index 100% rename from core/cache.ts rename to src/core/cache.ts diff --git a/core/configure.ts b/src/core/configure.ts similarity index 100% rename from core/configure.ts rename to src/core/configure.ts diff --git a/core/logger.ts b/src/core/logger.ts similarity index 100% rename from core/logger.ts rename to src/core/logger.ts diff --git a/core/mod.ts b/src/core/mod.ts similarity index 100% rename from core/mod.ts rename to src/core/mod.ts diff --git a/error/error-codes.ts b/src/error/error-codes.ts similarity index 100% rename from error/error-codes.ts rename to src/error/error-codes.ts diff --git a/error/raise.ts b/src/error/raise.ts similarity index 100% rename from error/raise.ts rename to src/error/raise.ts diff --git a/extensions/array/includes-any.ts b/src/extensions/array/includes-any.ts similarity index 100% rename from extensions/array/includes-any.ts rename to src/extensions/array/includes-any.ts diff --git a/extensions/bigint/to-json.ts b/src/extensions/bigint/to-json.ts similarity index 100% rename from extensions/bigint/to-json.ts rename to src/extensions/bigint/to-json.ts diff --git a/extensions/date/is-after-or-equal.ts b/src/extensions/date/is-after-or-equal.ts similarity index 100% rename from extensions/date/is-after-or-equal.ts rename to src/extensions/date/is-after-or-equal.ts diff --git a/extensions/date/is-after.ts b/src/extensions/date/is-after.ts similarity index 100% rename from extensions/date/is-after.ts rename to src/extensions/date/is-after.ts diff --git a/extensions/date/is-before-or-equal.ts b/src/extensions/date/is-before-or-equal.ts similarity index 100% rename from extensions/date/is-before-or-equal.ts rename to src/extensions/date/is-before-or-equal.ts diff --git a/extensions/date/is-before.ts b/src/extensions/date/is-before.ts similarity index 100% rename from extensions/date/is-before.ts rename to src/extensions/date/is-before.ts diff --git a/extensions/date/set-midnight.ts b/src/extensions/date/set-midnight.ts similarity index 100% rename from extensions/date/set-midnight.ts rename to src/extensions/date/set-midnight.ts diff --git a/extensions/string/empty.ts b/src/extensions/string/empty.ts similarity index 100% rename from extensions/string/empty.ts rename to src/extensions/string/empty.ts diff --git a/filesystem/file.ts b/src/filesystem/file.ts similarity index 100% rename from filesystem/file.ts rename to src/filesystem/file.ts diff --git a/filesystem/folder.ts b/src/filesystem/folder.ts similarity index 100% rename from filesystem/folder.ts rename to src/filesystem/folder.ts diff --git a/queue/queue.ts b/src/queue/queue.ts similarity index 100% rename from queue/queue.ts rename to src/queue/queue.ts diff --git a/queue/scheduler/first-in-first-out.ts b/src/queue/scheduler/first-in-first-out.ts similarity index 100% rename from queue/scheduler/first-in-first-out.ts rename to src/queue/scheduler/first-in-first-out.ts diff --git a/queue/scheduler/last-in-first-out.ts b/src/queue/scheduler/last-in-first-out.ts similarity index 100% rename from queue/scheduler/last-in-first-out.ts rename to src/queue/scheduler/last-in-first-out.ts diff --git a/queue/scheduler/weighted-first-in-first-out.ts b/src/queue/scheduler/weighted-first-in-first-out.ts similarity index 100% rename from queue/scheduler/weighted-first-in-first-out.ts rename to src/queue/scheduler/weighted-first-in-first-out.ts diff --git a/security/hash.ts b/src/security/hash.ts similarity index 100% rename from security/hash.ts rename to src/security/hash.ts diff --git a/security/password.ts b/src/security/password.ts similarity index 100% rename from security/password.ts rename to src/security/password.ts diff --git a/security/random.ts b/src/security/random.ts similarity index 100% rename from security/random.ts rename to src/security/random.ts diff --git a/utility/check-source.ts b/src/utility/check-source.ts similarity index 100% rename from utility/check-source.ts rename to src/utility/check-source.ts diff --git a/utility/contract.ts b/src/utility/contract.ts similarity index 100% rename from utility/contract.ts rename to src/utility/contract.ts diff --git a/utility/cron.ts b/src/utility/cron.ts similarity index 100% rename from utility/cron.ts rename to src/utility/cron.ts diff --git a/utility/empty.ts b/src/utility/empty.ts similarity index 100% rename from utility/empty.ts rename to src/utility/empty.ts diff --git a/utility/error-or-data.ts b/src/utility/error-or-data.ts similarity index 100% rename from utility/error-or-data.ts rename to src/utility/error-or-data.ts diff --git a/utility/fetch-with-timeout.ts b/src/utility/fetch-with-timeout.ts similarity index 100% rename from utility/fetch-with-timeout.ts rename to src/utility/fetch-with-timeout.ts diff --git a/utility/format-bytes.ts b/src/utility/format-bytes.ts similarity index 100% rename from utility/format-bytes.ts rename to src/utility/format-bytes.ts diff --git a/utility/inflector.ts b/src/utility/inflector.ts similarity index 100% rename from utility/inflector.ts rename to src/utility/inflector.ts diff --git a/utility/name-of.ts b/src/utility/name-of.ts similarity index 100% rename from utility/name-of.ts rename to src/utility/name-of.ts diff --git a/utility/parse-arguments.ts b/src/utility/parse-arguments.ts similarity index 100% rename from utility/parse-arguments.ts rename to src/utility/parse-arguments.ts diff --git a/utility/registry.ts b/src/utility/registry.ts similarity index 100% rename from utility/registry.ts rename to src/utility/registry.ts diff --git a/utility/sleep.ts b/src/utility/sleep.ts similarity index 100% rename from utility/sleep.ts rename to src/utility/sleep.ts diff --git a/utility/text.ts b/src/utility/text.ts similarity index 100% rename from utility/text.ts rename to src/utility/text.ts diff --git a/utility/time-string.ts b/src/utility/time-string.ts similarity index 100% rename from utility/time-string.ts rename to src/utility/time-string.ts diff --git a/utility/time.ts b/src/utility/time.ts similarity index 100% rename from utility/time.ts rename to src/utility/time.ts diff --git a/utility/value-or-default.ts b/src/utility/value-or-default.ts similarity index 100% rename from utility/value-or-default.ts rename to src/utility/value-or-default.ts diff --git a/validation/rules.ts b/src/validation/rules.ts similarity index 100% rename from validation/rules.ts rename to src/validation/rules.ts diff --git a/validation/rules/is-empty.ts b/src/validation/rules/is-empty.ts similarity index 100% rename from validation/rules/is-empty.ts rename to src/validation/rules/is-empty.ts diff --git a/validation/rules/is-null.ts b/src/validation/rules/is-null.ts similarity index 100% rename from validation/rules/is-null.ts rename to src/validation/rules/is-null.ts diff --git a/validation/rules/is-undefined.ts b/src/validation/rules/is-undefined.ts similarity index 100% rename from validation/rules/is-undefined.ts rename to src/validation/rules/is-undefined.ts diff --git a/validation/rules/max-length.ts b/src/validation/rules/max-length.ts similarity index 100% rename from validation/rules/max-length.ts rename to src/validation/rules/max-length.ts diff --git a/validation/rules/min-length.ts b/src/validation/rules/min-length.ts similarity index 100% rename from validation/rules/min-length.ts rename to src/validation/rules/min-length.ts diff --git a/validation/validator.ts b/src/validation/validator.ts similarity index 100% rename from validation/validator.ts rename to src/validation/validator.ts diff --git a/webserver/controller/component.ts b/src/webserver/controller/component.ts similarity index 100% rename from webserver/controller/component.ts rename to src/webserver/controller/component.ts diff --git a/webserver/controller/controller.ts b/src/webserver/controller/controller.ts similarity index 100% rename from webserver/controller/controller.ts rename to src/webserver/controller/controller.ts diff --git a/webserver/controller/mod.ts b/src/webserver/controller/mod.ts similarity index 100% rename from webserver/controller/mod.ts rename to src/webserver/controller/mod.ts diff --git a/webserver/http/mod.ts b/src/webserver/http/mod.ts similarity index 100% rename from webserver/http/mod.ts rename to src/webserver/http/mod.ts diff --git a/webserver/http/request.ts b/src/webserver/http/request.ts similarity index 100% rename from webserver/http/request.ts rename to src/webserver/http/request.ts diff --git a/webserver/http/response-builder.ts b/src/webserver/http/response-builder.ts similarity index 100% rename from webserver/http/response-builder.ts rename to src/webserver/http/response-builder.ts diff --git a/webserver/http/status-codes.ts b/src/webserver/http/status-codes.ts similarity index 100% rename from webserver/http/status-codes.ts rename to src/webserver/http/status-codes.ts diff --git a/webserver/mod.ts b/src/webserver/mod.ts similarity index 100% rename from webserver/mod.ts rename to src/webserver/mod.ts diff --git a/webserver/pathToRegexp.ts b/src/webserver/pathToRegexp.ts similarity index 100% rename from webserver/pathToRegexp.ts rename to src/webserver/pathToRegexp.ts diff --git a/webserver/registry/registry.ts b/src/webserver/registry/registry.ts similarity index 100% rename from webserver/registry/registry.ts rename to src/webserver/registry/registry.ts diff --git a/webserver/renderers/handlebars.ts b/src/webserver/renderers/handlebars.ts similarity index 100% rename from webserver/renderers/handlebars.ts rename to src/webserver/renderers/handlebars.ts diff --git a/webserver/renderers/json.ts b/src/webserver/renderers/json.ts similarity index 100% rename from webserver/renderers/json.ts rename to src/webserver/renderers/json.ts diff --git a/webserver/renderers/mod.ts b/src/webserver/renderers/mod.ts similarity index 100% rename from webserver/renderers/mod.ts rename to src/webserver/renderers/mod.ts diff --git a/webserver/renderers/octet-stream.ts b/src/webserver/renderers/octet-stream.ts similarity index 100% rename from webserver/renderers/octet-stream.ts rename to src/webserver/renderers/octet-stream.ts diff --git a/webserver/renderers/plaintext.ts b/src/webserver/renderers/plaintext.ts similarity index 100% rename from webserver/renderers/plaintext.ts rename to src/webserver/renderers/plaintext.ts diff --git a/webserver/routing/mod.ts b/src/webserver/routing/mod.ts similarity index 100% rename from webserver/routing/mod.ts rename to src/webserver/routing/mod.ts diff --git a/webserver/routing/route.ts b/src/webserver/routing/route.ts similarity index 100% rename from webserver/routing/route.ts rename to src/webserver/routing/route.ts diff --git a/webserver/routing/router.ts b/src/webserver/routing/router.ts similarity index 100% rename from webserver/routing/router.ts rename to src/webserver/routing/router.ts diff --git a/webserver/webserver.ts b/src/webserver/webserver.ts similarity index 100% rename from webserver/webserver.ts rename to src/webserver/webserver.ts diff --git a/websocket/authenticator.ts b/src/websocket/authenticator.ts similarity index 100% rename from websocket/authenticator.ts rename to src/websocket/authenticator.ts diff --git a/websocket/events.ts b/src/websocket/events.ts similarity index 100% rename from websocket/events.ts rename to src/websocket/events.ts diff --git a/websocket/mod.ts b/src/websocket/mod.ts similarity index 100% rename from websocket/mod.ts rename to src/websocket/mod.ts diff --git a/websocket/websocket.ts b/src/websocket/websocket.ts similarity index 100% rename from websocket/websocket.ts rename to src/websocket/websocket.ts From 7c3cb67ece7df3a5a899d9fbaac32d1aad1f3441 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 23:31:05 +0100 Subject: [PATCH 357/379] Fix small error --- src/communication/couchdb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/communication/couchdb.ts b/src/communication/couchdb.ts index 7ca944ea..76afc4c0 100644 --- a/src/communication/couchdb.ts +++ b/src/communication/couchdb.ts @@ -1,4 +1,4 @@ -import { Auth, CouchResponse, CouchRequest, CachedResponse, CouchOverrides} from "../@types/couchdb.ts"; +import { Auth, CouchResponse, CouchRequest, CachedResponse, CouchOverrides} from "../../types/couchdb.ts"; import { Cache } from "../core/cache.ts"; import { Configure } from "../core/configure.ts"; From 4f53830ca6edff3bf9f22c0e14a832859ae8cd5e Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 23:34:17 +0100 Subject: [PATCH 358/379] Fix small error --- src/security/password.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/security/password.ts b/src/security/password.ts index 17f37223..0e8aa0d9 100644 --- a/src/security/password.ts +++ b/src/security/password.ts @@ -1,5 +1,5 @@ -import { Algorithms, INSECURE_ALGORITHMS } from "../types/hash.ts"; -import { PasswordOptions, HASH_IDENTIFIERS } from "../types/password.ts"; +import { Algorithms, INSECURE_ALGORITHMS } from "../../types/hash.ts"; +import { PasswordOptions, HASH_IDENTIFIERS } from "../../types/password.ts"; import { Hash } from "./hash.ts"; import { Random } from "./random.ts"; From b660a6826b3dc00d77da5a8ca7f496745ec1e3fa Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 23:44:10 +0100 Subject: [PATCH 359/379] Allow definition of static salt for testing purposes --- src/security/password.ts | 29 ++++++++++++++++++----------- types/password.ts | 5 +++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/security/password.ts b/src/security/password.ts index 0e8aa0d9..20c5bdfa 100644 --- a/src/security/password.ts +++ b/src/security/password.ts @@ -2,7 +2,8 @@ import { Algorithms, INSECURE_ALGORITHMS } from "../../types/hash.ts"; import { PasswordOptions, HASH_IDENTIFIERS } from "../../types/password.ts"; import { Hash } from "./hash.ts"; import { Random } from "./random.ts"; - +import {Logger, raise} from "../../mod.ts"; +import {valueOrDefault} from "../utility/value-or-default.ts"; /** * Recommended hashing algorithm for most use-cases. @@ -10,8 +11,6 @@ import { Random } from "./random.ts"; */ export const PASSWORD_DEFAULT = Algorithms.SHA3_256; - - /** * Default options for password hashing. * These defaults offer a good balance between performance and security. @@ -45,24 +44,32 @@ export class Password { options: PasswordOptions = DEFAULT_OPTS, ): Promise { // Make sure we are not using an insecure algorithm - if (INSECURE_ALGORITHMS.includes(algo) && !options.allowInsecure) { - throw Error("Insecure hashing algorithm selected, aborting."); - } + const isUsingInsecureAlgorithm = INSECURE_ALGORITHMS.includes(algo); + const mayUseInsecureAlgorithms = !options.allowInsecure; + if (isUsingInsecureAlgorithm && !mayUseInsecureAlgorithms) raise("Insecure hashing algorithm selected, aborting."); // Make sure cost is set, else, use a default - if (typeof options.cost !== "number" || options.cost <= 0) options.cost = DEFAULT_OPTS.cost; + const cost = valueOrDefault(options.cost, 0); + const costIsAboveZero = cost > 0; + if (!costIsAboveZero) options.cost = DEFAULT_OPTS.cost; // Get our identifier const identifierIndex = Object.values(HASH_IDENTIFIERS).indexOf(algo as unknown as HASH_IDENTIFIERS); if (!identifierIndex) throw Error(`Identifier for algorithm "${algo}" could not be found!`); const identifier = Object.keys(HASH_IDENTIFIERS)[identifierIndex]; - // Create our hash - const salt = await Random.string(32); - const result = await Password.doHash(password, algo, salt, options.cost!); + // Create salt if need be + if(options.salt === undefined) { + options.salt = Random.string(32); + } else { + Logger.warning("Using statically defined salt, this is not suitable for production usage!"); + } + + // Hash our password + const result = await Password.doHash(password, algo, options.salt, options.cost!); // Return our final hash string - return `${identifier}!${options.cost}!${salt}!${result}`; + return `${identifier}!${options.cost}!${options.salt}!${result}`; } /** diff --git a/types/password.ts b/types/password.ts index e1f7c938..a422cf31 100644 --- a/types/password.ts +++ b/types/password.ts @@ -44,4 +44,9 @@ export interface PasswordOptions { cost?: number; /* Allow the use of insecure algorithms */ allowInsecure?: boolean; + /** + * Specify a static salt + * Usage of this should be limited to testing only! + */ + salt?: string; } From 37a2d8eba0ae6eeb3f9c2cacfcd3f3d04d766a8b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 23:58:06 +0100 Subject: [PATCH 360/379] Fix bunch of paths --- .gitignore | 4 +- common.ts | 8 +- mod.ts | 73 ++++++++++--------- src/communication/influxdb.ts | 2 +- src/communication/loki.ts | 2 +- src/communication/nut.ts | 2 +- src/communication/rcon.ts | 2 +- src/communication/uptime-kuma.ts | 4 +- src/core/cache.ts | 2 +- src/core/configure.ts | 3 +- src/core/logger.ts | 2 +- src/queue/queue.ts | 2 +- src/queue/scheduler/first-in-first-out.ts | 2 +- src/queue/scheduler/last-in-first-out.ts | 2 +- .../scheduler/weighted-first-in-first-out.ts | 2 +- src/security/hash.ts | 2 +- src/utility/check-source.ts | 2 +- src/utility/error-or-data.ts | 2 +- src/validation/rules.ts | 2 +- src/validation/rules/is-empty.ts | 4 +- src/validation/rules/is-null.ts | 2 +- src/validation/rules/is-undefined.ts | 2 +- src/validation/rules/max-length.ts | 2 +- src/validation/rules/min-length.ts | 2 +- src/validation/validator.ts | 2 +- src/webserver/controller/controller.ts | 2 +- src/webserver/http/request.ts | 2 +- src/webserver/http/response-builder.ts | 2 +- src/webserver/pathToRegexp.ts | 2 +- src/webserver/renderers/handlebars.ts | 2 +- src/webserver/renderers/json.ts | 2 +- src/webserver/renderers/octet-stream.ts | 2 +- src/webserver/renderers/plaintext.ts | 2 +- src/webserver/routing/router.ts | 2 +- src/websocket/events.ts | 2 +- tests/common/configure.test.ts | 2 +- tests/error/raise.test.ts | 2 +- tests/extensions/array.test.ts | 2 +- tests/extensions/date.test.ts | 10 +-- tests/extensions/string.test.ts | 2 +- tests/queue/queue.test.ts | 8 +- tests/utility/contract.test.ts | 2 +- tests/utility/error-or-data.test.ts | 2 +- tests/utility/inflector.test.ts | 2 +- tests/utility/name-of.test.ts | 2 +- tests/utility/text.test.ts | 2 +- 46 files changed, 95 insertions(+), 95 deletions(-) diff --git a/.gitignore b/.gitignore index b48929bc..abad7e81 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,8 @@ /.idea # Ignore reports -/coverage +/src/coverage /cov.lcov # Ignore docs -/docs +/src/docs diff --git a/common.ts b/common.ts index 28199d7e..1c381d62 100644 --- a/common.ts +++ b/common.ts @@ -2,7 +2,7 @@ * These are just the exports you'll most commonly use. * You can view the "docs"-directory to see what else there is! */ -export { Cache, Configure, Logger } from "./core/mod.ts"; -export { File } from "./filesystem/file.ts"; -export { Folder } from "./filesystem/folder.ts"; -export { CheckSource } from "./utility/check-source.ts"; +export { Cache, Configure, Logger } from "./src/core/mod.ts"; +export { File } from "./src/filesystem/file.ts"; +export { Folder } from "./src/filesystem/folder.ts"; +export { CheckSource } from "./src/utility/check-source.ts"; diff --git a/mod.ts b/mod.ts index 68387bc1..ee7256ea 100644 --- a/mod.ts +++ b/mod.ts @@ -1,71 +1,72 @@ /** * Communication */ -export { CouchDB } from "./communication/couchdb.ts"; -export { Druid } from "./communication/druid.ts"; -export { GraphQL } from "./communication/graphql.ts"; -export { InfluxDB } from "./communication/influxdb.ts"; -export { Loki } from "./communication/loki.ts"; -export { Ntfy } from "./communication/ntfy.ts"; -export { Nut } from "./communication/nut.ts"; -export { RCON } from "./communication/rcon.ts"; -export { Redis } from "./communication/redis.ts"; -export { UptimeKuma } from "./communication/uptime-kuma.ts"; +export { CouchDB } from "./src/communication/couchdb.ts"; +export { Druid } from "./src/communication/druid.ts"; +export { GraphQL } from "./src/communication/graphql.ts"; +export { InfluxDB } from "./src/communication/influxdb.ts"; +export { Loki } from "./src/communication/loki.ts"; +export { Ntfy } from "./src/communication/ntfy.ts"; +export { Nut } from "./src/communication/nut.ts"; +export { RCON } from "./src/communication/rcon.ts"; +export { Redis } from "./src/communication/redis.ts"; +export { UptimeKuma } from "./src/communication/uptime-kuma.ts"; /** * Chomp Core */ -export * from "./core/mod.ts"; +export * from "./src/core/mod.ts"; /** * Error */ -export type { ErrorCodes } from "./error/error-codes.ts"; -export { raise } from "./error/raise.ts"; +export type { ErrorCodes } from "./src/error/error-codes.ts"; +export { raise } from "./src/error/raise.ts"; /** * Filesystem */ -export { File } from "./filesystem/file.ts"; -export { Folder } from "./filesystem/folder.ts"; +export { File } from "./src/filesystem/file.ts"; +export { Folder } from "./src/filesystem/folder.ts"; /** * Queue */ -export { Queue } from "./queue/queue.ts"; +export { Queue } from "./src/queue/queue.ts"; /** * Security */ -export { Hash } from "./security/hash.ts"; -export { Password } from "./security/password.ts"; -export { Random } from "./security/random.ts"; -export type { Algorithms, INSECURE_ALGORITHMS } from "./security/hash.ts"; -export type { DEFAULT_OPTS, PASSWORD_DEFAULT, PasswordOptions } from "./security/password.ts"; +export { Hash } from "./src/security/hash.ts"; +export { Password } from "./src/security/password.ts"; +export { Random } from "./src/security/random.ts"; +export type { Algorithms, INSECURE_ALGORITHMS } from "./types/hash.ts"; +export type { DEFAULT_OPTS, PASSWORD_DEFAULT } from "./src/security/password.ts"; +export type { PasswordOptions } from "./types/password.ts"; /** * Utility */ -export { CheckSource } from "./utility/check-source.ts"; -export { Contract } from "./utility/contract.ts"; -export { Cron } from "./utility/cron.ts"; -export { empty } from "./utility/empty.ts"; -export { errorOrData } from "./utility/error-or-data.ts"; -export { fetchWithTimeout } from "./utility/fetch-with-timeout.ts"; -export { formatBytes } from "./utility/format-bytes.ts"; -export { Inflector } from "./utility/inflector.ts"; -export { nameOf } from "./utility/name-of.ts"; -export { Text } from "./utility/text.ts"; -export { Time } from "./utility/time.ts"; -export { TimeString, TimeStringSeconds } from "./utility/time-string.ts"; -export type { ExclusionConfig } from "./utility/check-source.ts"; +export { CheckSource } from "./src/utility/check-source.ts"; +export { Contract } from "./src/utility/contract.ts"; +export { Cron } from "./src/utility/cron.ts"; +export { empty } from "./src/utility/empty.ts"; +export { errorOrData } from "./src/utility/error-or-data.ts"; +export { fetchWithTimeout } from "./src/utility/fetch-with-timeout.ts"; +export { formatBytes } from "./src/utility/format-bytes.ts"; +export { Inflector } from "./src/utility/inflector.ts"; +export { nameOf } from "./src/utility/name-of.ts"; +export { Text } from "./src/utility/text.ts"; +export { Time } from "./src/utility/time.ts"; +export { TimeString, TimeStringSeconds } from "./src/utility/time-string.ts"; +export type { ExclusionConfig } from "./types/check-source.ts"; /** * Webserver */ -export * from "./webserver/mod.ts"; +export * from "./src/webserver/mod.ts"; /** * Websocket */ -export * from "./websocket/mod.ts"; +export * from "./src/websocket/mod.ts"; diff --git a/src/communication/influxdb.ts b/src/communication/influxdb.ts index a2284994..facdfd62 100644 --- a/src/communication/influxdb.ts +++ b/src/communication/influxdb.ts @@ -1,4 +1,4 @@ -import { Precision, Api } from "../types/influxdb.ts"; +import { Precision, Api } from "../../types/influxdb.ts"; import { Logger } from "../core/logger.ts"; /** diff --git a/src/communication/loki.ts b/src/communication/loki.ts index 6d948070..fcc97dbb 100644 --- a/src/communication/loki.ts +++ b/src/communication/loki.ts @@ -1,4 +1,4 @@ -import { LokiStream } from "../types/loki.ts"; +import { LokiStream } from "../../types/loki.ts"; import { Logger } from "../core/logger.ts"; /** diff --git a/src/communication/nut.ts b/src/communication/nut.ts index 67ae3db8..0d264ca8 100644 --- a/src/communication/nut.ts +++ b/src/communication/nut.ts @@ -1,4 +1,4 @@ -import { NutState } from "../types/nut.ts"; +import { NutState } from "../../types/nut.ts"; import { Logger } from "../core/logger.ts"; /** diff --git a/src/communication/rcon.ts b/src/communication/rcon.ts index 1c1f0219..f7ba223a 100644 --- a/src/communication/rcon.ts +++ b/src/communication/rcon.ts @@ -1,4 +1,4 @@ -import { PacketType } from "../types/rcon.ts"; +import { PacketType } from "../../types/rcon.ts"; import { Buffer } from "https://deno.land/std@0.87.0/node/buffer.ts"; /** diff --git a/src/communication/uptime-kuma.ts b/src/communication/uptime-kuma.ts index 7f09d40c..3432fbf9 100644 --- a/src/communication/uptime-kuma.ts +++ b/src/communication/uptime-kuma.ts @@ -1,6 +1,6 @@ -import { UptimeKumaInstance } from "../types/uptime-kuma.ts"; +import { UptimeKumaInstance } from "../../types/uptime-kuma.ts"; import {fetchWithTimeout} from "../utility/fetch-with-timeout.ts"; -import {raise} from "../mod.ts"; +import {raise} from "../../mod.ts"; /** * Interact with an Uptime Kuma instance. diff --git a/src/core/cache.ts b/src/core/cache.ts index 276a8e33..31329493 100644 --- a/src/core/cache.ts +++ b/src/core/cache.ts @@ -1,4 +1,4 @@ -import { CacheItem, CacheMetrics } from "../types/cache.ts"; +import { CacheItem, CacheMetrics } from "../../types/cache.ts"; import { TimeString } from "../utility/time-string.ts"; import { Logger } from "./logger.ts"; import { Configure } from "./configure.ts"; diff --git a/src/core/configure.ts b/src/core/configure.ts index 8a635a80..029cb8d3 100644 --- a/src/core/configure.ts +++ b/src/core/configure.ts @@ -1,5 +1,4 @@ -import { LogLevels } from "../types/logging.ts"; -import {Logger} from "./logger.ts"; +import {Logger, LogLevels} from "./logger.ts"; import {valueOrDefault} from "../utility/value-or-default.ts"; import { File } from "../filesystem/file.ts"; import {empty} from "../utility/empty.ts"; diff --git a/src/core/logger.ts b/src/core/logger.ts index 3c543c6f..02c59b08 100644 --- a/src/core/logger.ts +++ b/src/core/logger.ts @@ -1,4 +1,4 @@ -import { LogLevels, LogLevelKeys, LogHandlers, LogLevelHandlerKeys } from "../types/logging.ts"; +import { LogLevels, LogLevelKeys, LogHandlers, LogLevelHandlerKeys } from "../../types/logging.ts"; import { Time } from "../utility/time.ts"; import { Configure } from "./configure.ts"; import { bold, cyan, magenta, red, yellow, blue, green, gray } from "https://deno.land/std@0.117.0/fmt/colors.ts"; diff --git a/src/queue/queue.ts b/src/queue/queue.ts index b23c820a..ef44597a 100644 --- a/src/queue/queue.ts +++ b/src/queue/queue.ts @@ -1,4 +1,4 @@ -import { QueueItem, Scheduler } from "../types/queue.ts"; +import { QueueItem, Scheduler } from "../../types/queue.ts"; import { default as defaultScheduler } from "./scheduler/first-in-first-out.ts"; /** diff --git a/src/queue/scheduler/first-in-first-out.ts b/src/queue/scheduler/first-in-first-out.ts index 69c249b4..eef316a7 100644 --- a/src/queue/scheduler/first-in-first-out.ts +++ b/src/queue/scheduler/first-in-first-out.ts @@ -1,4 +1,4 @@ -import {QueueItem} from "../../types/queue.ts"; +import {QueueItem} from "../../../types/queue.ts"; export default function(item: QueueItem, items: QueueItem[] = []) { // Remove weight if specified diff --git a/src/queue/scheduler/last-in-first-out.ts b/src/queue/scheduler/last-in-first-out.ts index d82d7d29..74cc54d1 100644 --- a/src/queue/scheduler/last-in-first-out.ts +++ b/src/queue/scheduler/last-in-first-out.ts @@ -1,4 +1,4 @@ -import {QueueItem} from "../../types/queue.ts"; +import {QueueItem} from "../../../types/queue.ts"; export default function(item: QueueItem, items: QueueItem[] = []) { // Remove weight if specified diff --git a/src/queue/scheduler/weighted-first-in-first-out.ts b/src/queue/scheduler/weighted-first-in-first-out.ts index b33a11e4..7e71a34f 100644 --- a/src/queue/scheduler/weighted-first-in-first-out.ts +++ b/src/queue/scheduler/weighted-first-in-first-out.ts @@ -1,4 +1,4 @@ -import {QueueItem} from "../../types/queue.ts"; +import {QueueItem} from "../../../types/queue.ts"; import {valueOrDefault} from "../../utility/value-or-default.ts"; export default function(item: QueueItem, items: QueueItem[] = []) { diff --git a/src/security/hash.ts b/src/security/hash.ts index d2a5d5cb..7f31c71d 100644 --- a/src/security/hash.ts +++ b/src/security/hash.ts @@ -1,4 +1,4 @@ -import { Algorithms } from "../types/hash.ts"; +import { Algorithms } from "../../types/hash.ts"; import { DigestAlgorithm } from "https://cdn.deno.land/std/versions/0.113.0/raw/_wasm_crypto/mod.ts"; import { crypto } from "https://deno.land/std@0.113.0/crypto/mod.ts"; diff --git a/src/utility/check-source.ts b/src/utility/check-source.ts index c6ada445..7f00796c 100644 --- a/src/utility/check-source.ts +++ b/src/utility/check-source.ts @@ -1,4 +1,4 @@ -import { ExclusionConfig } from "../types/check-source.ts"; +import { ExclusionConfig } from "../../types/check-source.ts"; import { Logger } from "../core/logger.ts"; import { File } from "../filesystem/file.ts"; diff --git a/src/utility/error-or-data.ts b/src/utility/error-or-data.ts index 84bae9a1..906a27a5 100644 --- a/src/utility/error-or-data.ts +++ b/src/utility/error-or-data.ts @@ -1,4 +1,4 @@ -import { SuccessResponse } from "../types/error-or-data.ts"; +import { SuccessResponse } from "../../types/error-or-data.ts"; export async function errorOrData Error>(promise: Promise, catchables?: E[]): Promise | [InstanceType]> { try { diff --git a/src/validation/rules.ts b/src/validation/rules.ts index 09470086..c2a08d98 100644 --- a/src/validation/rules.ts +++ b/src/validation/rules.ts @@ -1,4 +1,4 @@ -import { ValidationCallback } from "../types/validator.ts"; +import { ValidationCallback } from "../../types/validator.ts"; import { isEmpty } from "./rules/is-empty.ts"; import { isNull } from "./rules/is-null.ts"; import { isUndefined } from "./rules/is-undefined.ts"; diff --git a/src/validation/rules/is-empty.ts b/src/validation/rules/is-empty.ts index 2d20de50..f2ddb899 100644 --- a/src/validation/rules/is-empty.ts +++ b/src/validation/rules/is-empty.ts @@ -1,5 +1,5 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; -import {empty} from "../../mod.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; +import {empty} from "../../../mod.ts"; export function isEmpty(input: any, options: ValidationOptions): ValidationCallbackResponse { // Check if input is empty diff --git a/src/validation/rules/is-null.ts b/src/validation/rules/is-null.ts index e2d73dcc..5a226041 100644 --- a/src/validation/rules/is-null.ts +++ b/src/validation/rules/is-null.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; export function isNull(input: any, options: ValidationOptions): ValidationCallbackResponse { if(input === null) return [undefined]; diff --git a/src/validation/rules/is-undefined.ts b/src/validation/rules/is-undefined.ts index 99911fd6..45274071 100644 --- a/src/validation/rules/is-undefined.ts +++ b/src/validation/rules/is-undefined.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; export function isUndefined(input: any, options: ValidationOptions): ValidationCallbackResponse { if(input === undefined) return [undefined]; diff --git a/src/validation/rules/max-length.ts b/src/validation/rules/max-length.ts index ce5063ba..d7c467c6 100644 --- a/src/validation/rules/max-length.ts +++ b/src/validation/rules/max-length.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; import {valueOrDefault} from "../../utility/value-or-default.ts"; export function maxLength(input: any, options: ValidationOptions): ValidationCallbackResponse { diff --git a/src/validation/rules/min-length.ts b/src/validation/rules/min-length.ts index f8db33bc..d4d846d8 100644 --- a/src/validation/rules/min-length.ts +++ b/src/validation/rules/min-length.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; import {valueOrDefault} from "../../utility/value-or-default.ts"; export function minLength(input: any, options: ValidationOptions): ValidationCallbackResponse { diff --git a/src/validation/validator.ts b/src/validation/validator.ts index 405cf842..302bd0b7 100644 --- a/src/validation/validator.ts +++ b/src/validation/validator.ts @@ -1,4 +1,4 @@ -import { ValidationCallback, ValidationOptions, ValidationStep } from "../types/validator.ts"; +import { ValidationCallback, ValidationOptions, ValidationStep } from "../../types/validator.ts"; import {raise} from "../error/raise.ts"; import { Validators } from "./rules.ts"; diff --git a/src/webserver/controller/controller.ts b/src/webserver/controller/controller.ts index 17a1f9ac..6acf66ce 100644 --- a/src/webserver/controller/controller.ts +++ b/src/webserver/controller/controller.ts @@ -1,4 +1,4 @@ -import {ViewVariables} from "../../types/webserver.ts"; +import {ViewVariables} from "../../../types/webserver.ts"; import { Logger } from "../../core/logger.ts"; import { Inflector } from "../../utility/inflector.ts"; import {Handlebars, Json, OctetStream, Plaintext} from "../renderers/mod.ts"; diff --git a/src/webserver/http/request.ts b/src/webserver/http/request.ts index 613eae0c..011c6e51 100644 --- a/src/webserver/http/request.ts +++ b/src/webserver/http/request.ts @@ -1,4 +1,4 @@ -import { RequestParameters, QueryParameters } from "../../types/webserver.ts"; +import { RequestParameters, QueryParameters } from "../../../types/webserver.ts"; import { Route } from "../routing/route.ts"; export class Request { diff --git a/src/webserver/http/response-builder.ts b/src/webserver/http/response-builder.ts index 5ad4fa14..b3cf68f7 100644 --- a/src/webserver/http/response-builder.ts +++ b/src/webserver/http/response-builder.ts @@ -1,4 +1,4 @@ -import { ResponseHeader } from "../../types/webserver.ts"; +import { ResponseHeader } from "../../../types/webserver.ts"; import { StatusCodes } from "./status-codes.ts"; import { TimeString } from "../../utility/time-string.ts"; diff --git a/src/webserver/pathToRegexp.ts b/src/webserver/pathToRegexp.ts index 74df45c6..ce0f5701 100644 --- a/src/webserver/pathToRegexp.ts +++ b/src/webserver/pathToRegexp.ts @@ -9,7 +9,7 @@ import { PathFunction, TokensToFunctionOptions, ParseOptions -} from "../types/webserver.ts"; +} from "../../types/webserver.ts"; /** * Tokenize input string. diff --git a/src/webserver/renderers/handlebars.ts b/src/webserver/renderers/handlebars.ts index 47c1eb19..0abf7dc9 100644 --- a/src/webserver/renderers/handlebars.ts +++ b/src/webserver/renderers/handlebars.ts @@ -1,4 +1,4 @@ -import { ViewVariables } from "../../types/webserver.ts"; +import { ViewVariables } from "../../../types/webserver.ts"; import { default as hbs } from "https://jspm.dev/handlebars@4.7.6"; import { Cache } from "../../core/cache.ts"; diff --git a/src/webserver/renderers/json.ts b/src/webserver/renderers/json.ts index 95a4c8e5..6a11048f 100644 --- a/src/webserver/renderers/json.ts +++ b/src/webserver/renderers/json.ts @@ -1,4 +1,4 @@ -import {ViewVariables} from "../../types/webserver.ts"; +import {ViewVariables} from "../../../types/webserver.ts"; export class Json { public static render( diff --git a/src/webserver/renderers/octet-stream.ts b/src/webserver/renderers/octet-stream.ts index 001ea449..381e2711 100644 --- a/src/webserver/renderers/octet-stream.ts +++ b/src/webserver/renderers/octet-stream.ts @@ -1,4 +1,4 @@ -import {ViewVariables} from "../../types/webserver.ts"; +import {ViewVariables} from "../../../types/webserver.ts"; export class OctetStream { public static render( diff --git a/src/webserver/renderers/plaintext.ts b/src/webserver/renderers/plaintext.ts index a1f9ca38..57a93a1b 100644 --- a/src/webserver/renderers/plaintext.ts +++ b/src/webserver/renderers/plaintext.ts @@ -1,4 +1,4 @@ -import {ViewVariables} from "../../types/webserver.ts"; +import {ViewVariables} from "../../../types/webserver.ts"; export class Plaintext { public static render( diff --git a/src/webserver/routing/router.ts b/src/webserver/routing/router.ts index bef1ab38..2c3bfb02 100644 --- a/src/webserver/routing/router.ts +++ b/src/webserver/routing/router.ts @@ -1,4 +1,4 @@ -import { Route, QueryParameters, RequestParameters } from "../../types/webserver.ts"; +import { Route, QueryParameters, RequestParameters } from "../../../types/webserver.ts"; import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts"; import { readAll } from "https://deno.land/std@0.213.0/io/read_all.ts"; import { pathToRegexp } from "../pathToRegexp.ts"; diff --git a/src/websocket/events.ts b/src/websocket/events.ts index 759bfd09..2243dea5 100644 --- a/src/websocket/events.ts +++ b/src/websocket/events.ts @@ -1,4 +1,4 @@ -import { IEvent } from "../types/websocket.ts"; +import { IEvent } from "../../types/websocket.ts"; import { Logger } from "../core/logger.ts"; export class Events { diff --git a/tests/common/configure.test.ts b/tests/common/configure.test.ts index e7766797..f32c4570 100644 --- a/tests/common/configure.test.ts +++ b/tests/common/configure.test.ts @@ -1,5 +1,5 @@ import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { Configure } from "../../core/configure.ts"; +import { Configure } from "../../src/core/configure.ts"; Deno.test("Configure Test", () => { // Add a test variable and test against it diff --git a/tests/error/raise.test.ts b/tests/error/raise.test.ts index 266dec26..1b587c54 100644 --- a/tests/error/raise.test.ts +++ b/tests/error/raise.test.ts @@ -1,5 +1,5 @@ import { assertThrows } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { raise } from "../../error/raise.ts"; +import { raise } from "../../src/error/raise.ts"; class CustomError extends Error { constructor(public message: string) { diff --git a/tests/extensions/array.test.ts b/tests/extensions/array.test.ts index a420fec9..45fa47c6 100644 --- a/tests/extensions/array.test.ts +++ b/tests/extensions/array.test.ts @@ -1,4 +1,4 @@ -import "../../extensions/array/includes-any.ts"; +import "../../src/extensions/array/includes-any.ts"; import {assertEquals} from "https://deno.land/std@0.152.0/testing/asserts.ts"; Deno.test("Array Extensions", async (t) => { diff --git a/tests/extensions/date.test.ts b/tests/extensions/date.test.ts index 09ef71bc..707b98f3 100644 --- a/tests/extensions/date.test.ts +++ b/tests/extensions/date.test.ts @@ -1,8 +1,8 @@ -import "../../extensions/date/is-after.ts"; -import "../../extensions/date/is-after-or-equal.ts"; -import "../../extensions/date/is-before.ts"; -import "../../extensions/date/is-before-or-equal.ts"; -import "../../extensions/date/set-midnight.ts"; +import "../../src/extensions/date/is-after.ts"; +import "../../src/extensions/date/is-after-or-equal.ts"; +import "../../src/extensions/date/is-before.ts"; +import "../../src/extensions/date/is-before-or-equal.ts"; +import "../../src/extensions/date/set-midnight.ts"; import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; Deno.test("Date Extensions Test", async (t) => { diff --git a/tests/extensions/string.test.ts b/tests/extensions/string.test.ts index 8ee6c795..936f2bed 100644 --- a/tests/extensions/string.test.ts +++ b/tests/extensions/string.test.ts @@ -1,4 +1,4 @@ -import "../../extensions/string/empty.ts"; +import "../../src/extensions/string/empty.ts"; import {assertEquals} from "https://deno.land/std@0.152.0/testing/asserts.ts"; Deno.test("String Extensions", async (t) => { diff --git a/tests/queue/queue.test.ts b/tests/queue/queue.test.ts index a1e393fe..16429c46 100644 --- a/tests/queue/queue.test.ts +++ b/tests/queue/queue.test.ts @@ -1,8 +1,8 @@ import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { Queue } from "../../queue/queue.ts"; -import { default as fifo } from "../../queue/scheduler/first-in-first-out.ts"; -import { default as lifo } from "../../queue/scheduler/last-in-first-out.ts"; -import { default as wfifo } from "../../queue/scheduler/weighted-first-in-first-out.ts"; +import { Queue } from "../../src/queue/queue.ts"; +import { default as fifo } from "../../src/queue/scheduler/first-in-first-out.ts"; +import { default as lifo } from "../../src/queue/scheduler/last-in-first-out.ts"; +import { default as wfifo } from "../../src/queue/scheduler/weighted-first-in-first-out.ts"; Deno.test("Queue Test", async (t) => { await t.step("Common", () => { diff --git a/tests/utility/contract.test.ts b/tests/utility/contract.test.ts index f780412f..0a97fe28 100644 --- a/tests/utility/contract.test.ts +++ b/tests/utility/contract.test.ts @@ -1,4 +1,4 @@ -import { Contract } from "../../utility/contract.ts"; +import { Contract } from "../../src/utility/contract.ts"; import { assert, assertThrows } from "https://deno.land/std@0.152.0/testing/asserts.ts"; Deno.test("Contract Test", async (t) => { diff --git a/tests/utility/error-or-data.test.ts b/tests/utility/error-or-data.test.ts index 79b1cdc7..b8dc5940 100644 --- a/tests/utility/error-or-data.test.ts +++ b/tests/utility/error-or-data.test.ts @@ -1,4 +1,4 @@ -import { errorOrData } from "../../utility/error-or-data.ts"; +import { errorOrData } from "../../src/utility/error-or-data.ts"; import { assertEquals, assertRejects, assertInstanceOf } from "https://deno.land/std@0.152.0/testing/asserts.ts"; import {assertNotInstanceOf} from "https://deno.land/std@0.159.0/testing/asserts.ts"; diff --git a/tests/utility/inflector.test.ts b/tests/utility/inflector.test.ts index 0a9e0d47..f7bf297e 100644 --- a/tests/utility/inflector.test.ts +++ b/tests/utility/inflector.test.ts @@ -1,4 +1,4 @@ -import { Inflector } from "../../utility/inflector.ts"; +import { Inflector } from "../../src/utility/inflector.ts"; import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; Deno.test("Inflector Test", async (t) => { diff --git a/tests/utility/name-of.test.ts b/tests/utility/name-of.test.ts index 38995d1a..788b4ec6 100644 --- a/tests/utility/name-of.test.ts +++ b/tests/utility/name-of.test.ts @@ -1,5 +1,5 @@ import { assertEquals, assertNotEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { nameOf } from "../../utility/name-of.ts"; +import { nameOf } from "../../src/utility/name-of.ts"; Deno.test("nameOf Test", () => { const testArgument = "blabla"; diff --git a/tests/utility/text.test.ts b/tests/utility/text.test.ts index 73fd12fc..f614a4a4 100644 --- a/tests/utility/text.test.ts +++ b/tests/utility/text.test.ts @@ -1,5 +1,5 @@ import { assertEquals, assertNotEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { Text } from "../../utility/text.ts"; +import { Text } from "../../src/utility/text.ts"; Deno.test("Text Test", async (t) => { await t.step("tokenize", () => { From 99227a55837e8502c018360b49cc59be4cf2c103 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Wed, 3 Dec 2025 23:58:31 +0100 Subject: [PATCH 361/379] Fix path --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index abad7e81..aa681aae 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ /.idea # Ignore reports -/src/coverage +/cov /cov.lcov # Ignore docs From c71d86d719ab15eec691f4460dfc566bcccf010b Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 4 Dec 2025 11:59:19 +0100 Subject: [PATCH 362/379] Move types into src folder --- src/communication/couchdb.ts | 2 +- {types => src/types}/cache.ts | 0 {types => src/types}/check-source.ts | 0 {types => src/types}/couchdb.ts | 0 {types => src/types}/error-or-data.ts | 0 {types => src/types}/hash.ts | 0 {types => src/types}/influxdb.ts | 0 {types => src/types}/logging.ts | 0 {types => src/types}/loki.ts | 0 {types => src/types}/nut.ts | 0 {types => src/types}/password.ts | 0 {types => src/types}/queue.ts | 0 {types => src/types}/rcon.ts | 0 {types => src/types}/uptime-kuma.ts | 0 {types => src/types}/validator.ts | 0 {types => src/types}/webserver.ts | 0 {types => src/types}/websocket.ts | 0 17 files changed, 1 insertion(+), 1 deletion(-) rename {types => src/types}/cache.ts (100%) rename {types => src/types}/check-source.ts (100%) rename {types => src/types}/couchdb.ts (100%) rename {types => src/types}/error-or-data.ts (100%) rename {types => src/types}/hash.ts (100%) rename {types => src/types}/influxdb.ts (100%) rename {types => src/types}/logging.ts (100%) rename {types => src/types}/loki.ts (100%) rename {types => src/types}/nut.ts (100%) rename {types => src/types}/password.ts (100%) rename {types => src/types}/queue.ts (100%) rename {types => src/types}/rcon.ts (100%) rename {types => src/types}/uptime-kuma.ts (100%) rename {types => src/types}/validator.ts (100%) rename {types => src/types}/webserver.ts (100%) rename {types => src/types}/websocket.ts (100%) diff --git a/src/communication/couchdb.ts b/src/communication/couchdb.ts index 76afc4c0..43193bda 100644 --- a/src/communication/couchdb.ts +++ b/src/communication/couchdb.ts @@ -1,4 +1,4 @@ -import { Auth, CouchResponse, CouchRequest, CachedResponse, CouchOverrides} from "../../types/couchdb.ts"; +import { Auth, CouchResponse, CouchRequest, CachedResponse, CouchOverrides} from "../types/couchdb.ts"; import { Cache } from "../core/cache.ts"; import { Configure } from "../core/configure.ts"; diff --git a/types/cache.ts b/src/types/cache.ts similarity index 100% rename from types/cache.ts rename to src/types/cache.ts diff --git a/types/check-source.ts b/src/types/check-source.ts similarity index 100% rename from types/check-source.ts rename to src/types/check-source.ts diff --git a/types/couchdb.ts b/src/types/couchdb.ts similarity index 100% rename from types/couchdb.ts rename to src/types/couchdb.ts diff --git a/types/error-or-data.ts b/src/types/error-or-data.ts similarity index 100% rename from types/error-or-data.ts rename to src/types/error-or-data.ts diff --git a/types/hash.ts b/src/types/hash.ts similarity index 100% rename from types/hash.ts rename to src/types/hash.ts diff --git a/types/influxdb.ts b/src/types/influxdb.ts similarity index 100% rename from types/influxdb.ts rename to src/types/influxdb.ts diff --git a/types/logging.ts b/src/types/logging.ts similarity index 100% rename from types/logging.ts rename to src/types/logging.ts diff --git a/types/loki.ts b/src/types/loki.ts similarity index 100% rename from types/loki.ts rename to src/types/loki.ts diff --git a/types/nut.ts b/src/types/nut.ts similarity index 100% rename from types/nut.ts rename to src/types/nut.ts diff --git a/types/password.ts b/src/types/password.ts similarity index 100% rename from types/password.ts rename to src/types/password.ts diff --git a/types/queue.ts b/src/types/queue.ts similarity index 100% rename from types/queue.ts rename to src/types/queue.ts diff --git a/types/rcon.ts b/src/types/rcon.ts similarity index 100% rename from types/rcon.ts rename to src/types/rcon.ts diff --git a/types/uptime-kuma.ts b/src/types/uptime-kuma.ts similarity index 100% rename from types/uptime-kuma.ts rename to src/types/uptime-kuma.ts diff --git a/types/validator.ts b/src/types/validator.ts similarity index 100% rename from types/validator.ts rename to src/types/validator.ts diff --git a/types/webserver.ts b/src/types/webserver.ts similarity index 100% rename from types/webserver.ts rename to src/types/webserver.ts diff --git a/types/websocket.ts b/src/types/websocket.ts similarity index 100% rename from types/websocket.ts rename to src/types/websocket.ts From a9b5cc866e8c2dc9c65e20122a365bb5db321610 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 4 Dec 2025 12:01:28 +0100 Subject: [PATCH 363/379] Seriously, why can't my Git client just pick up on this immediately? --- mod.ts | 6 +++--- src/communication/influxdb.ts | 2 +- src/communication/loki.ts | 2 +- src/communication/nut.ts | 2 +- src/communication/rcon.ts | 2 +- src/communication/uptime-kuma.ts | 2 +- src/core/cache.ts | 2 +- src/core/logger.ts | 2 +- src/queue/queue.ts | 2 +- src/queue/scheduler/first-in-first-out.ts | 2 +- src/queue/scheduler/last-in-first-out.ts | 2 +- src/queue/scheduler/weighted-first-in-first-out.ts | 2 +- src/security/hash.ts | 2 +- src/security/password.ts | 4 ++-- src/utility/check-source.ts | 2 +- src/utility/error-or-data.ts | 2 +- src/validation/rules.ts | 2 +- src/validation/rules/is-empty.ts | 2 +- src/validation/rules/is-null.ts | 2 +- src/validation/rules/is-undefined.ts | 2 +- src/validation/rules/max-length.ts | 2 +- src/validation/rules/min-length.ts | 2 +- src/validation/validator.ts | 2 +- src/webserver/controller/controller.ts | 2 +- src/webserver/http/request.ts | 2 +- src/webserver/http/response-builder.ts | 2 +- src/webserver/pathToRegexp.ts | 2 +- src/webserver/renderers/handlebars.ts | 2 +- src/webserver/renderers/json.ts | 2 +- src/webserver/renderers/octet-stream.ts | 2 +- src/webserver/renderers/plaintext.ts | 2 +- src/webserver/routing/router.ts | 2 +- src/websocket/events.ts | 2 +- 33 files changed, 36 insertions(+), 36 deletions(-) diff --git a/mod.ts b/mod.ts index ee7256ea..7d3032d9 100644 --- a/mod.ts +++ b/mod.ts @@ -40,9 +40,9 @@ export { Queue } from "./src/queue/queue.ts"; export { Hash } from "./src/security/hash.ts"; export { Password } from "./src/security/password.ts"; export { Random } from "./src/security/random.ts"; -export type { Algorithms, INSECURE_ALGORITHMS } from "./types/hash.ts"; +export type { Algorithms, INSECURE_ALGORITHMS } from "./src/types/hash.ts"; export type { DEFAULT_OPTS, PASSWORD_DEFAULT } from "./src/security/password.ts"; -export type { PasswordOptions } from "./types/password.ts"; +export type { PasswordOptions } from "./src/types/password.ts"; /** * Utility @@ -59,7 +59,7 @@ export { nameOf } from "./src/utility/name-of.ts"; export { Text } from "./src/utility/text.ts"; export { Time } from "./src/utility/time.ts"; export { TimeString, TimeStringSeconds } from "./src/utility/time-string.ts"; -export type { ExclusionConfig } from "./types/check-source.ts"; +export type { ExclusionConfig } from "./src/types/check-source.ts"; /** * Webserver diff --git a/src/communication/influxdb.ts b/src/communication/influxdb.ts index facdfd62..a2284994 100644 --- a/src/communication/influxdb.ts +++ b/src/communication/influxdb.ts @@ -1,4 +1,4 @@ -import { Precision, Api } from "../../types/influxdb.ts"; +import { Precision, Api } from "../types/influxdb.ts"; import { Logger } from "../core/logger.ts"; /** diff --git a/src/communication/loki.ts b/src/communication/loki.ts index fcc97dbb..6d948070 100644 --- a/src/communication/loki.ts +++ b/src/communication/loki.ts @@ -1,4 +1,4 @@ -import { LokiStream } from "../../types/loki.ts"; +import { LokiStream } from "../types/loki.ts"; import { Logger } from "../core/logger.ts"; /** diff --git a/src/communication/nut.ts b/src/communication/nut.ts index 0d264ca8..67ae3db8 100644 --- a/src/communication/nut.ts +++ b/src/communication/nut.ts @@ -1,4 +1,4 @@ -import { NutState } from "../../types/nut.ts"; +import { NutState } from "../types/nut.ts"; import { Logger } from "../core/logger.ts"; /** diff --git a/src/communication/rcon.ts b/src/communication/rcon.ts index f7ba223a..1c1f0219 100644 --- a/src/communication/rcon.ts +++ b/src/communication/rcon.ts @@ -1,4 +1,4 @@ -import { PacketType } from "../../types/rcon.ts"; +import { PacketType } from "../types/rcon.ts"; import { Buffer } from "https://deno.land/std@0.87.0/node/buffer.ts"; /** diff --git a/src/communication/uptime-kuma.ts b/src/communication/uptime-kuma.ts index 3432fbf9..a7429c37 100644 --- a/src/communication/uptime-kuma.ts +++ b/src/communication/uptime-kuma.ts @@ -1,4 +1,4 @@ -import { UptimeKumaInstance } from "../../types/uptime-kuma.ts"; +import { UptimeKumaInstance } from "../types/uptime-kuma.ts"; import {fetchWithTimeout} from "../utility/fetch-with-timeout.ts"; import {raise} from "../../mod.ts"; diff --git a/src/core/cache.ts b/src/core/cache.ts index 31329493..276a8e33 100644 --- a/src/core/cache.ts +++ b/src/core/cache.ts @@ -1,4 +1,4 @@ -import { CacheItem, CacheMetrics } from "../../types/cache.ts"; +import { CacheItem, CacheMetrics } from "../types/cache.ts"; import { TimeString } from "../utility/time-string.ts"; import { Logger } from "./logger.ts"; import { Configure } from "./configure.ts"; diff --git a/src/core/logger.ts b/src/core/logger.ts index 02c59b08..3c543c6f 100644 --- a/src/core/logger.ts +++ b/src/core/logger.ts @@ -1,4 +1,4 @@ -import { LogLevels, LogLevelKeys, LogHandlers, LogLevelHandlerKeys } from "../../types/logging.ts"; +import { LogLevels, LogLevelKeys, LogHandlers, LogLevelHandlerKeys } from "../types/logging.ts"; import { Time } from "../utility/time.ts"; import { Configure } from "./configure.ts"; import { bold, cyan, magenta, red, yellow, blue, green, gray } from "https://deno.land/std@0.117.0/fmt/colors.ts"; diff --git a/src/queue/queue.ts b/src/queue/queue.ts index ef44597a..b23c820a 100644 --- a/src/queue/queue.ts +++ b/src/queue/queue.ts @@ -1,4 +1,4 @@ -import { QueueItem, Scheduler } from "../../types/queue.ts"; +import { QueueItem, Scheduler } from "../types/queue.ts"; import { default as defaultScheduler } from "./scheduler/first-in-first-out.ts"; /** diff --git a/src/queue/scheduler/first-in-first-out.ts b/src/queue/scheduler/first-in-first-out.ts index eef316a7..69c249b4 100644 --- a/src/queue/scheduler/first-in-first-out.ts +++ b/src/queue/scheduler/first-in-first-out.ts @@ -1,4 +1,4 @@ -import {QueueItem} from "../../../types/queue.ts"; +import {QueueItem} from "../../types/queue.ts"; export default function(item: QueueItem, items: QueueItem[] = []) { // Remove weight if specified diff --git a/src/queue/scheduler/last-in-first-out.ts b/src/queue/scheduler/last-in-first-out.ts index 74cc54d1..d82d7d29 100644 --- a/src/queue/scheduler/last-in-first-out.ts +++ b/src/queue/scheduler/last-in-first-out.ts @@ -1,4 +1,4 @@ -import {QueueItem} from "../../../types/queue.ts"; +import {QueueItem} from "../../types/queue.ts"; export default function(item: QueueItem, items: QueueItem[] = []) { // Remove weight if specified diff --git a/src/queue/scheduler/weighted-first-in-first-out.ts b/src/queue/scheduler/weighted-first-in-first-out.ts index 7e71a34f..b33a11e4 100644 --- a/src/queue/scheduler/weighted-first-in-first-out.ts +++ b/src/queue/scheduler/weighted-first-in-first-out.ts @@ -1,4 +1,4 @@ -import {QueueItem} from "../../../types/queue.ts"; +import {QueueItem} from "../../types/queue.ts"; import {valueOrDefault} from "../../utility/value-or-default.ts"; export default function(item: QueueItem, items: QueueItem[] = []) { diff --git a/src/security/hash.ts b/src/security/hash.ts index 7f31c71d..d2a5d5cb 100644 --- a/src/security/hash.ts +++ b/src/security/hash.ts @@ -1,4 +1,4 @@ -import { Algorithms } from "../../types/hash.ts"; +import { Algorithms } from "../types/hash.ts"; import { DigestAlgorithm } from "https://cdn.deno.land/std/versions/0.113.0/raw/_wasm_crypto/mod.ts"; import { crypto } from "https://deno.land/std@0.113.0/crypto/mod.ts"; diff --git a/src/security/password.ts b/src/security/password.ts index 20c5bdfa..df429aab 100644 --- a/src/security/password.ts +++ b/src/security/password.ts @@ -1,5 +1,5 @@ -import { Algorithms, INSECURE_ALGORITHMS } from "../../types/hash.ts"; -import { PasswordOptions, HASH_IDENTIFIERS } from "../../types/password.ts"; +import { Algorithms, INSECURE_ALGORITHMS } from "../types/hash.ts"; +import { PasswordOptions, HASH_IDENTIFIERS } from "../types/password.ts"; import { Hash } from "./hash.ts"; import { Random } from "./random.ts"; import {Logger, raise} from "../../mod.ts"; diff --git a/src/utility/check-source.ts b/src/utility/check-source.ts index 7f00796c..c6ada445 100644 --- a/src/utility/check-source.ts +++ b/src/utility/check-source.ts @@ -1,4 +1,4 @@ -import { ExclusionConfig } from "../../types/check-source.ts"; +import { ExclusionConfig } from "../types/check-source.ts"; import { Logger } from "../core/logger.ts"; import { File } from "../filesystem/file.ts"; diff --git a/src/utility/error-or-data.ts b/src/utility/error-or-data.ts index 906a27a5..84bae9a1 100644 --- a/src/utility/error-or-data.ts +++ b/src/utility/error-or-data.ts @@ -1,4 +1,4 @@ -import { SuccessResponse } from "../../types/error-or-data.ts"; +import { SuccessResponse } from "../types/error-or-data.ts"; export async function errorOrData Error>(promise: Promise, catchables?: E[]): Promise | [InstanceType]> { try { diff --git a/src/validation/rules.ts b/src/validation/rules.ts index c2a08d98..09470086 100644 --- a/src/validation/rules.ts +++ b/src/validation/rules.ts @@ -1,4 +1,4 @@ -import { ValidationCallback } from "../../types/validator.ts"; +import { ValidationCallback } from "../types/validator.ts"; import { isEmpty } from "./rules/is-empty.ts"; import { isNull } from "./rules/is-null.ts"; import { isUndefined } from "./rules/is-undefined.ts"; diff --git a/src/validation/rules/is-empty.ts b/src/validation/rules/is-empty.ts index f2ddb899..929c681f 100644 --- a/src/validation/rules/is-empty.ts +++ b/src/validation/rules/is-empty.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; import {empty} from "../../../mod.ts"; export function isEmpty(input: any, options: ValidationOptions): ValidationCallbackResponse { diff --git a/src/validation/rules/is-null.ts b/src/validation/rules/is-null.ts index 5a226041..e2d73dcc 100644 --- a/src/validation/rules/is-null.ts +++ b/src/validation/rules/is-null.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; export function isNull(input: any, options: ValidationOptions): ValidationCallbackResponse { if(input === null) return [undefined]; diff --git a/src/validation/rules/is-undefined.ts b/src/validation/rules/is-undefined.ts index 45274071..99911fd6 100644 --- a/src/validation/rules/is-undefined.ts +++ b/src/validation/rules/is-undefined.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; export function isUndefined(input: any, options: ValidationOptions): ValidationCallbackResponse { if(input === undefined) return [undefined]; diff --git a/src/validation/rules/max-length.ts b/src/validation/rules/max-length.ts index d7c467c6..ce5063ba 100644 --- a/src/validation/rules/max-length.ts +++ b/src/validation/rules/max-length.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; import {valueOrDefault} from "../../utility/value-or-default.ts"; export function maxLength(input: any, options: ValidationOptions): ValidationCallbackResponse { diff --git a/src/validation/rules/min-length.ts b/src/validation/rules/min-length.ts index d4d846d8..f8db33bc 100644 --- a/src/validation/rules/min-length.ts +++ b/src/validation/rules/min-length.ts @@ -1,4 +1,4 @@ -import {ValidationCallbackResponse, ValidationOptions} from "../../../types/validator.ts"; +import {ValidationCallbackResponse, ValidationOptions} from "../../types/validator.ts"; import {valueOrDefault} from "../../utility/value-or-default.ts"; export function minLength(input: any, options: ValidationOptions): ValidationCallbackResponse { diff --git a/src/validation/validator.ts b/src/validation/validator.ts index 302bd0b7..405cf842 100644 --- a/src/validation/validator.ts +++ b/src/validation/validator.ts @@ -1,4 +1,4 @@ -import { ValidationCallback, ValidationOptions, ValidationStep } from "../../types/validator.ts"; +import { ValidationCallback, ValidationOptions, ValidationStep } from "../types/validator.ts"; import {raise} from "../error/raise.ts"; import { Validators } from "./rules.ts"; diff --git a/src/webserver/controller/controller.ts b/src/webserver/controller/controller.ts index 6acf66ce..17a1f9ac 100644 --- a/src/webserver/controller/controller.ts +++ b/src/webserver/controller/controller.ts @@ -1,4 +1,4 @@ -import {ViewVariables} from "../../../types/webserver.ts"; +import {ViewVariables} from "../../types/webserver.ts"; import { Logger } from "../../core/logger.ts"; import { Inflector } from "../../utility/inflector.ts"; import {Handlebars, Json, OctetStream, Plaintext} from "../renderers/mod.ts"; diff --git a/src/webserver/http/request.ts b/src/webserver/http/request.ts index 011c6e51..613eae0c 100644 --- a/src/webserver/http/request.ts +++ b/src/webserver/http/request.ts @@ -1,4 +1,4 @@ -import { RequestParameters, QueryParameters } from "../../../types/webserver.ts"; +import { RequestParameters, QueryParameters } from "../../types/webserver.ts"; import { Route } from "../routing/route.ts"; export class Request { diff --git a/src/webserver/http/response-builder.ts b/src/webserver/http/response-builder.ts index b3cf68f7..5ad4fa14 100644 --- a/src/webserver/http/response-builder.ts +++ b/src/webserver/http/response-builder.ts @@ -1,4 +1,4 @@ -import { ResponseHeader } from "../../../types/webserver.ts"; +import { ResponseHeader } from "../../types/webserver.ts"; import { StatusCodes } from "./status-codes.ts"; import { TimeString } from "../../utility/time-string.ts"; diff --git a/src/webserver/pathToRegexp.ts b/src/webserver/pathToRegexp.ts index ce0f5701..74df45c6 100644 --- a/src/webserver/pathToRegexp.ts +++ b/src/webserver/pathToRegexp.ts @@ -9,7 +9,7 @@ import { PathFunction, TokensToFunctionOptions, ParseOptions -} from "../../types/webserver.ts"; +} from "../types/webserver.ts"; /** * Tokenize input string. diff --git a/src/webserver/renderers/handlebars.ts b/src/webserver/renderers/handlebars.ts index 0abf7dc9..47c1eb19 100644 --- a/src/webserver/renderers/handlebars.ts +++ b/src/webserver/renderers/handlebars.ts @@ -1,4 +1,4 @@ -import { ViewVariables } from "../../../types/webserver.ts"; +import { ViewVariables } from "../../types/webserver.ts"; import { default as hbs } from "https://jspm.dev/handlebars@4.7.6"; import { Cache } from "../../core/cache.ts"; diff --git a/src/webserver/renderers/json.ts b/src/webserver/renderers/json.ts index 6a11048f..95a4c8e5 100644 --- a/src/webserver/renderers/json.ts +++ b/src/webserver/renderers/json.ts @@ -1,4 +1,4 @@ -import {ViewVariables} from "../../../types/webserver.ts"; +import {ViewVariables} from "../../types/webserver.ts"; export class Json { public static render( diff --git a/src/webserver/renderers/octet-stream.ts b/src/webserver/renderers/octet-stream.ts index 381e2711..001ea449 100644 --- a/src/webserver/renderers/octet-stream.ts +++ b/src/webserver/renderers/octet-stream.ts @@ -1,4 +1,4 @@ -import {ViewVariables} from "../../../types/webserver.ts"; +import {ViewVariables} from "../../types/webserver.ts"; export class OctetStream { public static render( diff --git a/src/webserver/renderers/plaintext.ts b/src/webserver/renderers/plaintext.ts index 57a93a1b..a1f9ca38 100644 --- a/src/webserver/renderers/plaintext.ts +++ b/src/webserver/renderers/plaintext.ts @@ -1,4 +1,4 @@ -import {ViewVariables} from "../../../types/webserver.ts"; +import {ViewVariables} from "../../types/webserver.ts"; export class Plaintext { public static render( diff --git a/src/webserver/routing/router.ts b/src/webserver/routing/router.ts index 2c3bfb02..bef1ab38 100644 --- a/src/webserver/routing/router.ts +++ b/src/webserver/routing/router.ts @@ -1,4 +1,4 @@ -import { Route, QueryParameters, RequestParameters } from "../../../types/webserver.ts"; +import { Route, QueryParameters, RequestParameters } from "../../types/webserver.ts"; import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts"; import { readAll } from "https://deno.land/std@0.213.0/io/read_all.ts"; import { pathToRegexp } from "../pathToRegexp.ts"; diff --git a/src/websocket/events.ts b/src/websocket/events.ts index 2243dea5..759bfd09 100644 --- a/src/websocket/events.ts +++ b/src/websocket/events.ts @@ -1,4 +1,4 @@ -import { IEvent } from "../../types/websocket.ts"; +import { IEvent } from "../types/websocket.ts"; import { Logger } from "../core/logger.ts"; export class Events { From b319422cc824da62a4f27a70da0b556a833c1546 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 8 Dec 2025 16:20:44 +0100 Subject: [PATCH 364/379] Fix bunch of errors, bugs and add tests for Hashing and Password creation/verification. --- src/security/password.ts | 25 +++++++++--------- tests/security/hash.test.ts | 18 +++++++++++++ tests/security/password.test.ts | 45 +++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 tests/security/hash.test.ts create mode 100644 tests/security/password.test.ts diff --git a/src/security/password.ts b/src/security/password.ts index df429aab..5ce06745 100644 --- a/src/security/password.ts +++ b/src/security/password.ts @@ -1,7 +1,7 @@ -import { Algorithms, INSECURE_ALGORITHMS } from "../types/hash.ts"; -import { PasswordOptions, HASH_IDENTIFIERS } from "../types/password.ts"; -import { Hash } from "./hash.ts"; -import { Random } from "./random.ts"; +import {Algorithms, INSECURE_ALGORITHMS} from "../types/hash.ts"; +import {HASH_IDENTIFIERS, PasswordOptions} from "../types/password.ts"; +import {Hash} from "./hash.ts"; +import {Random} from "./random.ts"; import {Logger, raise} from "../../mod.ts"; import {valueOrDefault} from "../utility/value-or-default.ts"; @@ -45,7 +45,7 @@ export class Password { ): Promise { // Make sure we are not using an insecure algorithm const isUsingInsecureAlgorithm = INSECURE_ALGORITHMS.includes(algo); - const mayUseInsecureAlgorithms = !options.allowInsecure; + const mayUseInsecureAlgorithms = options.allowInsecure; if (isUsingInsecureAlgorithm && !mayUseInsecureAlgorithms) raise("Insecure hashing algorithm selected, aborting."); // Make sure cost is set, else, use a default @@ -59,17 +59,17 @@ export class Password { const identifier = Object.keys(HASH_IDENTIFIERS)[identifierIndex]; // Create salt if need be - if(options.salt === undefined) { - options.salt = Random.string(32); - } else { + // Warn if we use a static salt + if(options.salt !== undefined) { Logger.warning("Using statically defined salt, this is not suitable for production usage!"); } + const salt = valueOrDefault(options.salt, Random.string(32)); // Hash our password - const result = await Password.doHash(password, algo, options.salt, options.cost!); + const result = await Password.doHash(password, algo, salt, options.cost!); // Return our final hash string - return `${identifier}!${options.cost}!${options.salt}!${result}`; + return `${identifier}!${options.cost}!${salt}!${result}`; } /** @@ -99,10 +99,11 @@ export class Password { private static async doHash(input: string, algo: string, salt: string, cost: number): Promise { const rounds = 2 ** cost; let result = input; + for (let round = 0; round < rounds; round++) { - const h = new Hash(`${salt}${input}`, algo); + const h = new Hash(`${salt}${input}`, algo as Algorithms); await h.digest(); - result = await h.hex(); + result = h.hex(); } return result; diff --git a/tests/security/hash.test.ts b/tests/security/hash.test.ts new file mode 100644 index 00000000..f7c009ae --- /dev/null +++ b/tests/security/hash.test.ts @@ -0,0 +1,18 @@ +import {Hash} from "../../src/security/hash.ts"; +import {Algorithms} from "../../src/types/hash.ts"; +import { assertEquals} from "https://deno.land/std@0.152.0/testing/asserts.ts"; + +Deno.test("Hash Test", async (t) => { + // Create Hash + const h = new Hash("test", Algorithms.SHA3_256); + + await t.step("Digest", async () => { + // TODO: Actually test it properly + // I can't find it out for the love of god + await h.digest(); + }); + + await t.step("Hex", () => { + assertEquals(h.hex(), "36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80"); + }); +}); diff --git a/tests/security/password.test.ts b/tests/security/password.test.ts new file mode 100644 index 00000000..b4078bdd --- /dev/null +++ b/tests/security/password.test.ts @@ -0,0 +1,45 @@ +import { Password } from "../../src/security/password.ts"; +import { Algorithms } from "../../src/types/hash.ts"; +import {assertEquals, assertNotEquals, assertRejects} from "https://deno.land/std@0.152.0/testing/asserts.ts"; + +const testHash = "d88!10!insecure-salt!a7129d5e75c40adc84235abac626f2bccd863600ad9db0dcc03950974bd8c9c1"; +const testPassword = "lamepassword"; +const invalidTestPassword = "incorrect-password"; +const testSalt = "insecure-salt"; +const insecureTestHash = "db7!10!insecure-salt!5d555c2d9ebfce2f53e138231ed3e3e9"; + +Deno.test("Password Test", async (t) => { + await t.step("Hash", async () => { + // Static salt + assertEquals( + await Password.hash(testPassword, Algorithms.SHA3_256, { + salt: testSalt, + }), + testHash + ); + + // Randomized salt + const a = await Password.hash(testPassword, Algorithms.SHA3_256); + const b = await Password.hash(testPassword, Algorithms.SHA3_256); + assertNotEquals(a, b); + }); + + await t.step("Verify", async () => { + assertEquals(await Password.verify(testPassword, testHash), true); + assertEquals(await Password.verify(invalidTestPassword, testHash), false); + }); + + await t.step("Insecure Algorithm Selection", async() => { + // Test when not allowing an insecure algorithm (default) + await assertRejects(async () => await Password.hash(testPassword, Algorithms.MD5)); + + // Test override + assertEquals( + await Password.hash(testPassword, Algorithms.MD5, { + salt: testSalt, + allowInsecure: true + }), + insecureTestHash + ); + }) +}); From 9a0f3ca76e4375f74dc63443dcddd4e0ae6533d2 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 8 Dec 2025 16:21:40 +0100 Subject: [PATCH 365/379] Update comment --- src/security/password.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/security/password.ts b/src/security/password.ts index 5ce06745..d122261d 100644 --- a/src/security/password.ts +++ b/src/security/password.ts @@ -26,6 +26,7 @@ export const DEFAULT_OPTS: PasswordOptions = { * * Heavily inspired by PHP's {@link https://www.php.net/manual/en/function.password-hash.php password_hash} * and {@link https://www.php.net/manual/en/function.password-verify.php password_verify} functions. + * However, not compatible with one and another at the moment. * * **NOTE**: If you want to create deterministic hashes, use the {@linkcode Hash} class instead! */ From 965482fa958590801201acc00d4558da4a4994f4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 8 Dec 2025 16:51:00 +0100 Subject: [PATCH 366/379] Fix bunch of bugs and write tests for built-in validator rules --- src/types/validator.ts | 4 +- src/validation/rules.ts | 4 +- src/validation/rules/is-empty.ts | 4 +- src/validation/rules/max-length.ts | 8 ++-- tests/validation/rules.test.ts | 68 ++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 tests/validation/rules.test.ts diff --git a/src/types/validator.ts b/src/types/validator.ts index 84bd4461..f9af6d04 100644 --- a/src/types/validator.ts +++ b/src/types/validator.ts @@ -2,7 +2,7 @@ export type ValidationCallback = (input: any, parameters: any) => ValidationCall export type ValidationCallbackResponse = ValidationCallbackSuccess|ValidationCallbackError; -export type ValidationCallbackParameters = ValidationParameter[]; +export type ValidationCallbackParameters = {[key: string]: any}; export type ValidationOptions = { last?: boolean; @@ -18,5 +18,3 @@ export type ValidationStep = { export type ValidationCallbackSuccess = [undefined]; export type ValidationCallbackError = [string]; - -export type ValidationParameter = {[key: string]: any}; diff --git a/src/validation/rules.ts b/src/validation/rules.ts index 09470086..6c06c157 100644 --- a/src/validation/rules.ts +++ b/src/validation/rules.ts @@ -2,8 +2,8 @@ import { ValidationCallback } from "../types/validator.ts"; import { isEmpty } from "./rules/is-empty.ts"; import { isNull } from "./rules/is-null.ts"; import { isUndefined } from "./rules/is-undefined.ts"; -import {minLength} from "./rules/min-length.ts"; -import {maxLength} from "./rules/max-length.ts"; +import { minLength } from "./rules/min-length.ts"; +import { maxLength } from "./rules/max-length.ts"; export const Validators = new Map([ ['isEmpty', isEmpty], diff --git a/src/validation/rules/is-empty.ts b/src/validation/rules/is-empty.ts index 929c681f..93d4eb02 100644 --- a/src/validation/rules/is-empty.ts +++ b/src/validation/rules/is-empty.ts @@ -5,8 +5,8 @@ export function isEmpty(input: any, options: ValidationOptions): ValidationCallb // Check if input is empty // If so, return the message const inputIsEmpty = empty(input); - if(inputIsEmpty) return [options.message]; + if(inputIsEmpty) return [undefined]; // We have something inside - return [undefined]; + return [options.message]; } diff --git a/src/validation/rules/max-length.ts b/src/validation/rules/max-length.ts index ce5063ba..1b2758fc 100644 --- a/src/validation/rules/max-length.ts +++ b/src/validation/rules/max-length.ts @@ -6,10 +6,10 @@ export function maxLength(input: any, options: ValidationOptions): ValidationCal // If not set, default to 0 const max = valueOrDefault(options.parameters?.length, 0); - // Check if we are below the maximum length + // Check if we are above the maximum length const maxLengthExceeded = input.length > max; - if(maxLengthExceeded) return [undefined]; + if(maxLengthExceeded) return [options.message]; - // Max length was exceeded - return [options.message]; + // Did not exceed max length + return [undefined]; } diff --git a/tests/validation/rules.test.ts b/tests/validation/rules.test.ts new file mode 100644 index 00000000..97111857 --- /dev/null +++ b/tests/validation/rules.test.ts @@ -0,0 +1,68 @@ +import { isEmpty } from "../../src/validation/rules/is-empty.ts"; +import { isNull } from "../../src/validation/rules/is-null.ts"; +import { isUndefined } from "../../src/validation/rules/is-undefined.ts"; +import { minLength } from "../../src/validation/rules/min-length.ts"; +import { maxLength } from "../../src/validation/rules/max-length.ts"; +import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; + +Deno.test("Validator Test", async (t) => { + await t.step("isEmpty", () => { + const message = "Passed argument not empty!"; + const params = {message: message} + + assertEquals(isEmpty([], params), [undefined]); + assertEquals(isEmpty([0], params), [message]); + }); + + await t.step("isNull", () => { + const message = "Passed argument not null!"; + const params = {message: message} + + assertEquals(isNull(null, params), [undefined]); + assertEquals(isNull(0, params), [message]); + }); + + await t.step("isUndefined", () => { + const message = "Passed argument not undefined!"; + const params = {message: message} + + assertEquals(isUndefined(undefined, params), [undefined]); + assertEquals(isUndefined(0, params), [message]); + }); + + await t.step("minLength", () => { + const message = "Passed argument not long enough!"; + const params = { + message: message, + parameters: { + length: 2 + } + }; + + // Test for strings + assertEquals(minLength("ab", params), [undefined]); + assertEquals(minLength("a", params), [message]); + + // Test for arrays + assertEquals(minLength([1,2], params), [undefined]); + assertEquals(minLength([1], params), [message]); + }); + + await t.step("maxLength", () => { + const message = "Passed argument too long!"; + const params = { + message: message, + parameters: { + length: 1 + } + }; + + // Test for strings + assertEquals(maxLength("a", params), [undefined]); + assertEquals(maxLength("ab", params), [message]); + + // Test for arrays + assertEquals(maxLength([1], params), [undefined]); + assertEquals(maxLength([1,2], params), [message]); + }); +}); From 368e74657be0d934ea08727744c0abd439f8b107 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 9 Dec 2025 12:22:23 +0100 Subject: [PATCH 367/379] Rename Test --- tests/validation/rules.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/validation/rules.test.ts b/tests/validation/rules.test.ts index 97111857..00bf0ced 100644 --- a/tests/validation/rules.test.ts +++ b/tests/validation/rules.test.ts @@ -5,7 +5,7 @@ import { minLength } from "../../src/validation/rules/min-length.ts"; import { maxLength } from "../../src/validation/rules/max-length.ts"; import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -Deno.test("Validator Test", async (t) => { +Deno.test("Validator Rules Test", async (t) => { await t.step("isEmpty", () => { const message = "Passed argument not empty!"; const params = {message: message} From b2fdda02f6573acd0cc153a0e13049e907c81a80 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 9 Dec 2025 12:37:05 +0100 Subject: [PATCH 368/379] Write test for Validation class --- tests/validation/validator.test.ts | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/validation/validator.test.ts diff --git a/tests/validation/validator.test.ts b/tests/validation/validator.test.ts new file mode 100644 index 00000000..b80d4eee --- /dev/null +++ b/tests/validation/validator.test.ts @@ -0,0 +1,36 @@ +import {assertEquals, assertThrows} from "https://deno.land/std@0.152.0/testing/asserts.ts"; +import {Validator} from "../../src/validation/validator.ts"; + + +Deno.test("Validator Test", async (t) => { + // Create Validator object + let validator = new Validator(); + + await t.step("Create Rule", () => { + validator.create('Mock Rule', () => [undefined]); + validator.create('Mock Rule', () => [undefined], true); + validator.create('Always Fail', () => ['Always fails']); + validator.create('Always Fail Again', () => ['Always fails as well']); + + assertThrows( + () => validator.create('Mock Rule', () => [undefined], false) + ) + }); + + await t.step("Add rule", () => { + validator.add('Mock Rule'); + }); + + await t.step("Execute Validators", () => { + assertEquals(validator.execute(0), []); + + validator.add('Always Fail'); + assertEquals(validator.execute(0), ['Always fails']); + }); + + await t.step("Stop on Failure", () => { + validator.add('Always Fail Again'); + validator.setStopOnFailure(true); + assertEquals(validator.execute(0), ['Always fails']); + }); +}); From a05d008ee079a713cfea37a51e8305393598f0a4 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 9 Dec 2025 12:48:43 +0100 Subject: [PATCH 369/379] Add envOrDefault --- src/utility/env-or-default.ts | 20 ++++++++++++++++++++ src/utility/time.ts | 4 +++- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/utility/env-or-default.ts diff --git a/src/utility/env-or-default.ts b/src/utility/env-or-default.ts new file mode 100644 index 00000000..3bc83bd3 --- /dev/null +++ b/src/utility/env-or-default.ts @@ -0,0 +1,20 @@ +/** + * Check if env variable has value, otherwise return a specified default + * + * @param key + * @param defaultValue + */ +export function envOrDefault(key: string, defaultValue: T|null = null): T { + // Check if we have permission + // If not, return the default + const hasPermission = Deno.permissions.querySync({name: "env" }).state === "granted"; + if(!hasPermission) return defaultValue as T; + + // Check if the env has a key + // If not, return the default + const hasKey = Deno.env.has(key); + if(!hasKey) return defaultValue as T; + + // Return the value specified by the env + return Deno.env.get(key) as T; +} diff --git a/src/utility/time.ts b/src/utility/time.ts index 2086159b..8864a687 100644 --- a/src/utility/time.ts +++ b/src/utility/time.ts @@ -1,6 +1,7 @@ import { time as timets } from "https://denopkg.com/burhanahmeed/time.ts@v2.0.1/mod.ts"; import { format as formatter } from "https://cdn.deno.land/std/versions/0.77.0/raw/datetime/mod.ts"; import { TimeString } from "./time-string.ts"; +import {envOrDefault} from "./env-or-default.ts"; /** * Try to alleviate the pain of working with time. @@ -38,7 +39,8 @@ export class Time { } public constructor(time: string | undefined = undefined) { - this.time = timets(time).tz(Deno.env.get("TZ")!).t; + const timezone = envOrDefault("TZ", "Europe/Amsterdam"); + this.time = timets(time).tz(timezone).t; } public format(format: string) { From 932c60e16b4cc54da732d90f93639016783340d6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Tue, 9 Dec 2025 13:00:17 +0100 Subject: [PATCH 370/379] Update Date extension test --- tests/extensions/date.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/extensions/date.test.ts b/tests/extensions/date.test.ts index 707b98f3..d489f331 100644 --- a/tests/extensions/date.test.ts +++ b/tests/extensions/date.test.ts @@ -36,8 +36,8 @@ Deno.test("Date Extensions Test", async (t) => { }); await t.step("setMidnight", () => { - assertEquals(c.getTime(), 1757973600000); - assertEquals(d.getTime(), 1758060000000); + assertEquals(c.toISOString(), '2025-09-15T22:00:00.000Z'); + assertEquals(d.toISOString(), '2025-09-16T22:00:00.000Z'); assertEquals(a.isBeforeOrEqual(b), true); assertEquals(b.isBeforeOrEqual(a), false); assertEquals(b.isBeforeOrEqual(b), true); From 5ad9c7500afb6d651c0141a98a63b543a7e75766 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 18 Dec 2025 11:34:48 +0100 Subject: [PATCH 371/379] Wrap serve in a try-catch and void promise --- src/webserver/webserver.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/webserver/webserver.ts b/src/webserver/webserver.ts index 43c0a279..54a58ea9 100644 --- a/src/webserver/webserver.ts +++ b/src/webserver/webserver.ts @@ -18,8 +18,12 @@ export class Webserver { // Serve connections for await (const conn of this.server) { - // @ts-ignore Left intentionally without await - this.serve(conn); + try { + // No need to await + void this.serve(conn); + } catch(e) { + Logger.error(`Could not serve connection: ${e.message}`, e.stack); + } } } From 5e4afc9f53703c35854f007d5fd26d1a3331d9c1 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Thu, 18 Dec 2025 11:42:43 +0100 Subject: [PATCH 372/379] Export component in controller mod --- src/webserver/controller/mod.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webserver/controller/mod.ts b/src/webserver/controller/mod.ts index 0632fe9d..35860cb6 100644 --- a/src/webserver/controller/mod.ts +++ b/src/webserver/controller/mod.ts @@ -1 +1,2 @@ +export * from "./component.ts"; export * from "./controller.ts"; From daf4ee8161cbd0f79b62be9af659873cd25f2782 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 22 Dec 2025 00:27:55 +0100 Subject: [PATCH 373/379] Void some promises --- src/websocket/websocket.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/websocket/websocket.ts b/src/websocket/websocket.ts index 2161f3a9..21a13522 100644 --- a/src/websocket/websocket.ts +++ b/src/websocket/websocket.ts @@ -30,12 +30,14 @@ export class Websocket { Logger.warning( `Closing connection with "${(client.webSocket.conn.remoteAddr as Deno.NetAddr).hostname!}": Invalid token!`, ); - client.close(1000, "Invalid authentication token!"); + // void: No need to await + void client.close(1000, "Invalid authentication token!"); return; } // Dispatch "ClientConnect" event - this.handleEvent("ClientConnect", { client: client }); + // void: No need to await + void this.handleEvent("ClientConnect", { client: client }); client.on("message", (message: string) => this.onMessage(message)); }); @@ -52,7 +54,8 @@ export class Websocket { for (const client of this.server.clients) { if (!client) continue; if (client.isClosed) continue; - client.send(JSON.stringify({ + // void: No need to await + void client.send(JSON.stringify({ event: eventString, data: data, })); From fe6c3728f93a363aca9903e25283583e4248f5e8 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 22 Dec 2025 00:29:27 +0100 Subject: [PATCH 374/379] Replace old hex function with the @std implementation as it's ~3x faster. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finlay@Richthoven > T:\repos\FinlayDaG33k\deno-lib 2025-12-22 00:27:15 00:27:15 >>> deno bench benchmarks/hex-encode-std.ts CPU | AMD Ryzen 9 5950X 16-Core Processor Runtime | Deno 1.46.3 (x86_64-pc-windows-msvc) file:///T:/repos/FinlayDaG33k/deno-lib/benchmarks/hex-encode-std.ts benchmark time/iter (avg) iter/s (min … max) p75 p99 p995 ------------------ ----------------------------- --------------------- -------------------------- Old Method 68.5 ms 14.6 ( 66.1 ms … 71.3 ms) 69.8 ms 71.3 ms 71.3 ms Standard Library 23.1 ms 43.3 ( 22.5 ms … 27.5 ms) 23.3 ms 27.5 ms 27.5 ms --- benchmarks/202512220028_hex-encode-std.ts | 31 +++++++++++++++++++++++ src/security/hash.ts | 3 ++- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 benchmarks/202512220028_hex-encode-std.ts diff --git a/benchmarks/202512220028_hex-encode-std.ts b/benchmarks/202512220028_hex-encode-std.ts new file mode 100644 index 00000000..3efb9220 --- /dev/null +++ b/benchmarks/202512220028_hex-encode-std.ts @@ -0,0 +1,31 @@ +import { encodeHex as std } from "jsr:@std/encoding@1.0.10"; +import { Random } from "../src/security/random.ts"; + +// Generate dataset +const dataset: Uint8Array[] = []; +for(let i = 0; i < 10_000; i++) { + dataset.push(Random.bytes(128)); +} + +/** + * Old hex encoding function + * + * @param input + */ +function old(input: Uint8Array): string { + return [...new Uint8Array(input)].map((x) => x.toString(16).padStart(2, "0")).join(""); +} + + +Deno.bench("Old Method", () => { + for(const entry of dataset) { + old(entry); + } +}); + +Deno.bench("Standard Library", () => { + for(const entry of dataset) { + std(entry); + } +}); + diff --git a/src/security/hash.ts b/src/security/hash.ts index d2a5d5cb..77a1625e 100644 --- a/src/security/hash.ts +++ b/src/security/hash.ts @@ -1,6 +1,7 @@ import { Algorithms } from "../types/hash.ts"; import { DigestAlgorithm } from "https://cdn.deno.land/std/versions/0.113.0/raw/_wasm_crypto/mod.ts"; import { crypto } from "https://deno.land/std@0.113.0/crypto/mod.ts"; +import { encodeHex } from "jsr:@std/encoding@1.0.10"; /** * Create hashes @@ -52,6 +53,6 @@ export class Hash { * ``` */ public hex() { - return [...new Uint8Array(this.result)].map((x) => x.toString(16).padStart(2, "0")).join(""); + return encodeHex(this.result); } } From 0ba0874c6cbdd2b00d933da0c18b70a14df5e0de Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 22 Dec 2025 01:16:01 +0100 Subject: [PATCH 375/379] Use URLPatterns for routing instead of yanky regex. --- src/types/webserver.ts | 4 +-- src/webserver/routing/route.ts | 4 +-- src/webserver/routing/router.ts | 50 +++++++++++---------------------- 3 files changed, 19 insertions(+), 39 deletions(-) diff --git a/src/types/webserver.ts b/src/types/webserver.ts index 8080b61e..d5f95505 100644 --- a/src/types/webserver.ts +++ b/src/types/webserver.ts @@ -1,8 +1,6 @@ export type ViewVariables = Map; -export interface RequestParameters { - [name: string]: string; -} +export type RequestParameters = Record; export interface QueryParameters { [name: string]: string; diff --git a/src/webserver/routing/route.ts b/src/webserver/routing/route.ts index 071b665d..ed83697d 100644 --- a/src/webserver/routing/route.ts +++ b/src/webserver/routing/route.ts @@ -1,13 +1,13 @@ export class Route { public constructor( - private readonly path: string, + private readonly path: URLPattern, private readonly controller: string, private readonly action: string, private readonly method: string, ) { } - public getPath(): typeof this.path { + public getPath(): URLPattern { return this.path; } diff --git a/src/webserver/routing/router.ts b/src/webserver/routing/router.ts index bef1ab38..f682e5b2 100644 --- a/src/webserver/routing/router.ts +++ b/src/webserver/routing/router.ts @@ -1,7 +1,6 @@ -import { Route, QueryParameters, RequestParameters } from "../../types/webserver.ts"; +import { Route, QueryParameters } from "../../types/webserver.ts"; import { readerFromStreamReader } from "https://deno.land/std@0.126.0/io/mod.ts"; import { readAll } from "https://deno.land/std@0.213.0/io/read_all.ts"; -import { pathToRegexp } from "../pathToRegexp.ts"; import { Inflector } from "../../utility/inflector.ts"; import { Logger } from "../../core/logger.ts"; import { Request as ChompRequest } from "../http/request.ts"; @@ -42,14 +41,18 @@ export class Router { if (route.getMethod() !== request.method) continue; // Make sure we have a matching route - const matches = pathToRegexp(route.getPath()).exec(path); - if (matches) { - return { - route: route, - path: path, - }; - } + const isMatch = route.getPath().test(request.url); + if(!isMatch) continue; + + return { + route: route, + path: path, + data: route.getPath().exec(request.url), + }; } + + // No suitable route was found + return null; } /** @@ -63,7 +66,8 @@ export class Router { // Make sure a route was found // Otherwise return a 404 response const route = Router.route(request); - if (!route || !route.route) { + const hasRoute = route !== null; + if (!hasRoute) { return new Response( "The requested page could not be found.", { @@ -82,7 +86,7 @@ export class Router { route.route, request.headers, await Router.getBody(request), - Router.getParams(route.route, route.path), + route.data!.pathname.groups, Router.getQuery(request.url), Router.getAuth(request), clientIp, @@ -154,28 +158,6 @@ export class Router { } } - /** - * Get the parameters for the given route - * - * @param route - * @param path - * @returns RequestParameters - */ - public static getParams(route: ChompRoute, path: string): RequestParameters { - // Strip off query parameters - const pathSplit = path.split("%3F"); - path = pathSplit[0]; - - const keys: string[] = []; - // TODO: Fix type error - // @ts-ignore -- - const r = pathToRegexp(route.getPath(), keys).exec(path) || []; - - // TODO: Fix type error - // @ts-ignore -- - return keys.reduce((acc, key, i) => ({ [key.name]: r[i + 1], ...acc }), {}); - } - /** * Get the query parameters for the given route * @@ -229,7 +211,7 @@ export class Router { public static add(route: Route): void { Router.routes.push( new ChompRoute( - route.path, + new URLPattern({pathname: route.path}), Inflector.pascalize(route.controller), route.action, route.method ?? "GET", From 75d7bd6ebdc7b915fe62bc7710f0a0b662efbda9 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 22 Dec 2025 01:56:07 +0100 Subject: [PATCH 376/379] Fix small errors --- src/webserver/http/request.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/webserver/http/request.ts b/src/webserver/http/request.ts index 613eae0c..6a0a2f37 100644 --- a/src/webserver/http/request.ts +++ b/src/webserver/http/request.ts @@ -1,5 +1,6 @@ import { RequestParameters, QueryParameters } from "../../types/webserver.ts"; import { Route } from "../routing/route.ts"; +import {valueOrDefault} from "../../utility/value-or-default.ts"; export class Request { constructor( @@ -40,8 +41,7 @@ export class Request { } public getParam(name: string): string | null { - if (name in this.params) return this.params[name]; - return null; + return valueOrDefault(this.params[name], null); } public getQueryParams(): QueryParameters { @@ -49,8 +49,7 @@ export class Request { } public getQuery(name: string): string | null { - if (name in this.query) return this.query[name]; - return null; + return valueOrDefault(this.query[name], null); } public getAuth(): string { From cd4a9b556346dd1ebc2cd3e0e5878fba1726cc57 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 22 Dec 2025 01:58:00 +0100 Subject: [PATCH 377/379] use valueOrDefault --- src/webserver/routing/router.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/webserver/routing/router.ts b/src/webserver/routing/router.ts index f682e5b2..1581c03f 100644 --- a/src/webserver/routing/router.ts +++ b/src/webserver/routing/router.ts @@ -9,6 +9,7 @@ import { Route as ChompRoute } from "./route.ts"; import { Controller } from "../controller/controller.ts"; import { Registry } from "../../utility/registry.ts"; import { raise } from "../../error/raise.ts"; +import {valueOrDefault} from "../../utility/value-or-default.ts"; export class Router { private static readonly _controllerDir = `file://${Deno.cwd()}/src/controller`; @@ -198,7 +199,7 @@ export class Router { public static getAuth(request: Request): string { // Get our authorization header // Return it or empty string if none found - return request.headers.get("authorization") ?? ""; + return valueOrDefault(request.headers.get("authorization"), ""); } /** @@ -214,7 +215,7 @@ export class Router { new URLPattern({pathname: route.path}), Inflector.pascalize(route.controller), route.action, - route.method ?? "GET", + valueOrDefault(route.method, "GET"), ), ); } From 8c7679936ef893440bb433b57659d7b146c71aa6 Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Mon, 22 Dec 2025 02:00:06 +0100 Subject: [PATCH 378/379] Use valueOrDefault --- src/webserver/http/response-builder.ts | 3 ++- src/websocket/websocket.ts | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/webserver/http/response-builder.ts b/src/webserver/http/response-builder.ts index 5ad4fa14..b3d0b1e1 100644 --- a/src/webserver/http/response-builder.ts +++ b/src/webserver/http/response-builder.ts @@ -1,6 +1,7 @@ import { ResponseHeader } from "../../types/webserver.ts"; import { StatusCodes } from "./status-codes.ts"; import { TimeString } from "../../utility/time-string.ts"; +import {valueOrDefault} from "../../utility/value-or-default.ts"; export class ResponseBuilder { private readonly _headers: Map> = new Map>(); @@ -26,7 +27,7 @@ export class ResponseBuilder { * @param name */ public getHeader(name: string): string[] { - return this._headers.get(name) ?? []; + return valueOrDefault(this._headers.get(name), []); } /** diff --git a/src/websocket/websocket.ts b/src/websocket/websocket.ts index 21a13522..c2323db9 100644 --- a/src/websocket/websocket.ts +++ b/src/websocket/websocket.ts @@ -3,6 +3,7 @@ import { Logger } from "../core/logger.ts"; import { Events } from "./events.ts"; import { Authenticator } from "./authenticator.ts"; import { Configure } from "../core/configure.ts"; +import {valueOrDefault} from "../utility/value-or-default.ts"; declare global { interface Window { @@ -21,7 +22,8 @@ export class Websocket { } public start() { - this.server = new WebSocketServer(this.port, Configure.get("real_ip_header", "X-Forwarded-For") ?? null); + const header = Configure.get("real_ip_header", "X-Forwarded-For"); + this.server = new WebSocketServer(this.port, valueOrDefault(header, null)); this.server.on("connection", (client: WebSocketAcceptedClient, url: string) => { Logger.info(`New WebSocket connection from "${(client.webSocket.conn.remoteAddr as Deno.NetAddr).hostname!}"...`); From f7433ea851d9c0950d9f1c892a57e506bbc9b12d Mon Sep 17 00:00:00 2001 From: Aroop Roelofs Date: Sun, 4 Jan 2026 21:01:01 +0100 Subject: [PATCH 379/379] Add test for Camelize --- tests/utility/inflector.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/utility/inflector.test.ts b/tests/utility/inflector.test.ts index f7bf297e..e67d9a20 100644 --- a/tests/utility/inflector.test.ts +++ b/tests/utility/inflector.test.ts @@ -19,6 +19,13 @@ Deno.test("Inflector Test", async (t) => { assertEquals(Inflector.pascalize("hello_World", "-"), "Hello_World"); }); + await t.step("camelize", () => { + assertEquals(Inflector.camelize("hello-world"), "hello-world"); + assertEquals(Inflector.camelize("hello_world"), "helloWorld"); + assertEquals(Inflector.camelize("hello-world", "-"), "helloWorld"); + assertEquals(Inflector.camelize("hello_world", "-"), "hello_world"); + }) + await t.step("humanize", () => { assertEquals(Inflector.humanize("hello-world"), "Hello-world"); assertEquals(Inflector.humanize("hello_World"), "Hello World");