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. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..0eaed6e1 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,53 @@ +name: Tests +on: + push: + branches: [main] + 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-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 + run: deno task coverage > cov.lcov + - name: upload coverage + uses: codecov/codecov-action@v4 + with: + 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/README.md b/README.md index 379d3717..632c8977 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,56 @@ # Chomp -Library of (arguably) useful Deno classes. -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 -Add the following to your file: + +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) +- [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](docs/discord/README.md) (Discordeno Wrapper): + ```ts -import * from "https://deno.land/x/chomp/mod.ts"; +import * from "https://deno.land/x/chomp/discord/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. +- [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) +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 -## 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. +Versions adhere to the following versioning system of `x.y.z` where: -| Library Version | Deno Version | -|-----------------|--------------| -| 1.1.0 | 1.24.0 | -| 1.0.0 | 1.15.3 | -| 0.0.2 | ??? | -| 0.0.1 | ??? | +- `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/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/common/configure.ts b/common/configure.ts deleted file mode 100644 index 0e6d9efd..00000000 --- a/common/configure.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { Logger } from "../logging/logger.ts"; - -export class Configure { - private static config = new Map([ - ['error_log', `${Deno.cwd()}/logs/error.log`] - ]); - private static hasLoaded = false; - - /** - * Load our configure date from file - * - * @param force Set to true to force re-loading the configure - * @returns void - */ - public static async load(force = false): Promise { - // Make sure we don't have loaded already - 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) { - Logger.warning(`Could not find file "config.json" at "${Deno.cwd()}". Configure will be empty!`); - Configure.hasLoaded = true; - return; - } - - // Read our JSON - try { - const json = await Deno.readTextFile(`${Deno.cwd()}/config.json`); - const data = JSON.parse(json); - for(const entry of Object.keys(data)) { - Configure.set(entry, data[entry]); - } - } catch(e) { - Logger.error(`Could not load JSON: "${e.message}"`, e.stack); - return; - } - - // Mark configure as loaded - Logger.info(`Finished loading Configure!`); - Configure.hasLoaded = true; - } - - /** - * 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 - */ - 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 - if(!Configure.config.has(key)) return defaultValue; - return Configure.config.get(key); - } - - /** - * Set a configure item - * - * @param key - * @param value - * @returns void - */ - public static set(key: string, value: any): void { - Configure.config.set(key, value); - } - - /** - * Return whether a key exists - * - * @param key - * @returns boolean - */ - public static check(key: string): boolean { - return Configure.config.has(key); - } - - 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; - - // Hack together a reference to our item's value - const ref = [Configure.config.get(key)]; - - // Delete the original item - Configure.config.delete(key); - - // Return the value - return ref[0]; - } - - /** - * Delete a ConfigureItem from the Configure - * - * @param key - * @returns void - */ - public static delete(key: string): void { - Configure.config.delete(key); - } - - /** - * Dump all contents of the Configure - * - * @returns ConfigureItem[] - */ - public static dump(): Map { - return Configure.config; - } - - /** - * Clear all items in the configure (including defaults) - * - * @returns void - */ - public static clear(): void { - Configure.config.clear(); - } -} diff --git a/common/cron.ts b/common/cron.ts deleted file mode 100644 index 2753eaa4..00000000 --- a/common/cron.ts +++ /dev/null @@ -1,140 +0,0 @@ -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(); 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."); diff --git a/common/time.ts b/common/time.ts deleted file mode 100644 index a1376bee..00000000 --- a/common/time.ts +++ /dev/null @@ -1,44 +0,0 @@ -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"; - -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 constructor(time: string|undefined = undefined) { - this.time = timets(time).tz(Deno.env.get('TZ')!).t; - } - - public format(format: string) { - return formatter(this.time, format); - } - - public midnight() { - this.time.setHours(0,0,0,0); - return this; - } - - public add(input: string) { - this.time.setMilliseconds(this.time.getMilliseconds() + T`${input}`); - return this; - } - - public addDay(days: number = 1) { - this.time.setDate(this.time.getDate() + days); - return this; - } - - public addWeek(weeks: number = 1) { - this.time.setDate(this.time.getDate() + (weeks * 7)); - return this; - } -} diff --git a/communication/couchdb.ts b/communication/couchdb.ts new file mode 100644 index 00000000..b9355d29 --- /dev/null +++ b/communication/couchdb.ts @@ -0,0 +1,353 @@ +interface Auth { + username: string; + password: string; +} + + +interface CouchRequest { + method: string; + headers: any; + body?: string; +} + +export interface CouchResponse { + status: number; + statusText: string; + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used + data: any | null; + error: null | { + error: string; + reason: string; + }; +} + +export interface CouchOverrides { + method?: string; +} + +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, + 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. + * + * @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) { + // 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. + * + * @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) { + // 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. + * + * @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 { + return await this.raw(id); + } + + /** + * 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 + 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. + * 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 + * @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; + 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. + * + * @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 + */ + // 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 + 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); + } + + /** + * 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 + */ + public async delete(id: string, revision: string): Promise { + 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}`); + } + + /** + * 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: any, fields?:string[]} = { + 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. + * + * @example + * ```ts + * // TODO: Write example + * ``` + * + * @param endpoint + * @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: CouchRequest = { + 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); + 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; + } + + return couchResponse; + } +} diff --git a/communication/druid.ts b/communication/druid.ts index af50ee03..dd9ddb35 100644 --- a/communication/druid.ts +++ b/communication/druid.ts @@ -1,7 +1,14 @@ export class Druid { + // deno-lint-ignore no-explicit-any -- TODO private spec: any = null; - public set setSpec(spec: any) { this.spec = spec; } - public get getSpec() { return this.spec; } + // deno-lint-ignore no-explicit-any -- TODO + public set setSpec(spec: any) { + this.spec = spec; + } + // deno-lint-ignore no-explicit-any -- TODO + public get getSpec(): any { + return this.spec; + } public constructor( private readonly host: string, @@ -14,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 new file mode 100644 index 00000000..398f6fd9 --- /dev/null +++ b/communication/graphql.ts @@ -0,0 +1,49 @@ +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 { + // TODO: Find out type + // @ts-ignore See TODO + this._variables[key] = value; + return this; + } +} diff --git a/communication/influxdb.ts b/communication/influxdb.ts new file mode 100644 index 00000000..3fcd9048 --- /dev/null +++ b/communication/influxdb.ts @@ -0,0 +1,158 @@ +import { Logger } from "../core/logger.ts"; + +export enum Precision { + s, + ms, + us, + ns, +} + +interface Api { + url: string; + auth: string; + precision: Precision; +} + +export class InfluxDB { + private _api: Api; + + public constructor( + url: string, + token: string, + org: string, + bucket: string, + precision: Precision = Precision.us + ) { + this._api = { + url: `${url}/api/v2/write?org=${org}&bucket=${bucket}&precision=${Precision[precision]}`, + auth: `Token ${token}`, + precision: precision, + }; + } + + /** + * Write our datapoint(s) to InfluxDB + * + * @param data + */ + 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, { + headers: { + Authorization: this._api.auth, + "Content-Type": "text/plain", + }, + method: "POST", + body: points, + }); + return resp.ok; + } catch (e) { + Logger.error(`Could not write point(s) 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; + } +} diff --git a/communication/loki.ts b/communication/loki.ts new file mode 100644 index 00000000..3653325d --- /dev/null +++ b/communication/loki.ts @@ -0,0 +1,42 @@ +import { Logger } from "../core/logger.ts"; + +export interface LokiStream { + // deno-lint-ignore no-explicit-any -- TODO + stream: any; + values: Array>; +} + +export 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); + } + } +} diff --git a/communication/ntfy.ts b/communication/ntfy.ts index 72b8cd15..85e75dc6 100644 --- a/communication/ntfy.ts +++ b/communication/ntfy.ts @@ -1,11 +1,11 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; 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 new file mode 100644 index 00000000..10118a95 --- /dev/null +++ b/communication/nut.ts @@ -0,0 +1,245 @@ +import { Logger } from "../core/logger.ts"; + +export class NutState { + public static readonly WAITING = 0; + public static readonly IDLE = 1; +} + +export class Nut { + 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 + 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(); + } + + // 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; + 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 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); + } + } + + 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) => { + // 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); + 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!"); + + // 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); + 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!"); + + // 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); + 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!"); + + // 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); + 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!"); + + // 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); + 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() { + // 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 + 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; + } + } + }); + }); + } +} diff --git a/communication/rcon.ts b/communication/rcon.ts index 8d4d5bbd..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"); } /** @@ -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); @@ -98,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 93b59d67..2fbe8987 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 { Logger } from "../logging/logger.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: any = null; + private static connection: RedisConn | null = null; /** * Connect to a Redis node @@ -11,21 +11,20 @@ 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, }); } /** * Return the redis connection - * TODO: Find out type of Redis.connection * * @return any */ - public static getConnection(): any { - if(!Redis.connection) Logger.error(`Redis connection requested before connecting!`); - return Redis.connection; + public static getConnection(): RedisConn { + if (!Redis.connection) Logger.error(`Redis connection requested before connecting!`); + return Redis.connection!; } } diff --git a/core/cache.ts b/core/cache.ts new file mode 100644 index 00000000..d9b4fbdf --- /dev/null +++ b/core/cache.ts @@ -0,0 +1,323 @@ +import { TimeString } from "../utility/time-string.ts"; +import { Logger } from "./logger.ts"; +import { Cron } from "../utility/cron.ts"; + +interface CacheItem { + data: unknown; + expires: Date | null; +} + +interface CacheMetrics { + reads: { + hit: number; + miss: number; + }; + writes: number; + swept: number; +} + +export class Cache { + private static _items: Map = new Map(); + private static _metrics: CacheMetrics = { + reads: { + hit: 0, + miss: 0 + }, + writes: 0, + swept: 0, + }; + + /** + * 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"; + * const metrics = Cache.metrics(); + * 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["reads"]|"rate"|"total"|"writes"|"swept"|"size"|null = null): number|CacheMetrics { + switch(key) { + case "hit": + return Cache._metrics.reads.hit; + case "miss": + return Cache._metrics.reads.miss; + case "total": + return Cache._metrics.reads.hit + Cache._metrics.reads.miss; + case "rate": { + const total: number = Cache.metrics("total") as number; + const percentile = +(Cache._metrics.reads.hit / total).toFixed(4); + if(percentile > 0) return percentile; + return 0; + } + case "writes": + return Cache._metrics.writes; + case "swept": + return Cache._metrics.swept; + case "size": + return Cache._items.size; + default: + return Cache._metrics; + } + } + + /** + * 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 + */ + 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, + }); + Cache._metrics.writes++; + } + + /** + * 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 + */ + public static get(key: string, optimistic = false): unknown | null { + // Return null if the item doesn't exist + if (!Cache.exists(key)) { + Cache._metrics.reads.miss++; + return null; + } + + // Return null if the item expired + if (Cache.expired(key) && !optimistic) { + Cache._metrics.reads.miss++; + return null; + } + + // Return the item's data + Cache._metrics.reads.hit++; + return Cache._items.get(key)?.data; + } + + /** + * 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 { + return Cache._items.has(key); + } + + /** + * 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 { + // If the item doesn't exist, 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; + 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. + * + * @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; + } + + /** + * 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 { + 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._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 + Cache.set(key, res, expiry); + + // Return result + return res; + } + + /** + * 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; + } + + /** + * 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 { + 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) { + // 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); + Cache._metrics.swept++; + } + + Logger.debug('Finished cache sweep!'); + } +} + +// Sweep cache every minute +// @ts-ignore It's a function not a type +Cron("0 */1 * * * *", () => Cache.sweep()); diff --git a/core/configure.ts b/core/configure.ts new file mode 100644 index 00000000..b988f082 --- /dev/null +++ b/core/configure.ts @@ -0,0 +1,234 @@ +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`], +]); + +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 + * + * @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 + */ + public static async load(force = false): Promise { + // Make sure we don't have loaded already + 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) { + Logger.warning(`Could not find file "config.json" at "${Deno.cwd()}". Configure will be empty!`); + Configure.hasLoaded = true; + return; + } + + // Read our JSON + try { + const json = await Deno.readTextFile(`${Deno.cwd()}/config.json`); + const data = JSON.parse(json); + for (const entry of Object.keys(data)) { + Configure.set(entry, data[entry]); + } + } catch (e) { + Logger.error(`Could not load JSON: "${e.message}"`, e.stack); + return; + } + + // Mark configure as loaded + Logger.info(`Finished loading Configure!`); + Configure.hasLoaded = true; + } + + /** + * 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 + * @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 { + // 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 + * + * @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 + */ + // 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); + } + + /** + * 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 + */ + public static check(key: string): boolean { + 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 + if (!Configure.config.has(key)) return defaultValue; + + // Hack together a reference to our item's value + const ref = [Configure.config.get(key)]; + + // Delete the original item + Configure.config.delete(key); + + // Return the value + return ref[0]; + } + + /** + * 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 + */ + public static delete(key: string): void { + Configure.config.delete(key); + } + + /** + * 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 + public static dump(): Map { + return Configure.config; + } + + /** + * Clear all items in the configure (including defaults). + * 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 + */ + 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. + * + * @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/core/logger.ts b/core/logger.ts new file mode 100644 index 00000000..8f9bbedd --- /dev/null +++ b/core/logger.ts @@ -0,0 +1,116 @@ +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"; + +type Handlers = { + info: (message: string) => void; + warning: (message: string) => 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 => { + // 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")) { + try { + let output = `[${now}] ERROR > ${message}`; + 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}`; + console.error(output); + }, + debug: (message: string): void => { + if (Configure.get("debug", false)) { + console.log(`[${Logger.time()}] ${magenta("DEBUG")} > ${message}`); + } + }, +}; + +export class Logger { + private static _handlers: Handlers = handlers; + + /** + * Override a handler app-wide. + * + * @param level {LogLevels} + * @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 { + Logger._handlers[level] = handler; + } + + /** + * 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); + } + + /** + * Write a warning message to the console + * + * @param {string} message The message to write + * @returns {void} + */ + 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 + */ + public static time(): string { + return new Time().format(Configure.get("logger.timeformat", "yyyy/MM/dd HH:mm:ss")); + } +} 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.json b/deno.json new file mode 100644 index 00000000..54fb79bc --- /dev/null +++ b/deno.json @@ -0,0 +1,21 @@ +{ + "fmt": { + "useTabs": false, + "singleQuote": false, + "semiColons": true, + "indentWidth": 2, + "lineWidth": 120, + "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" + } +} diff --git a/deno.lock b/deno.lock new file mode 100644 index 00000000..a187316c --- /dev/null +++ b/deno.lock @@ -0,0 +1,421 @@ +{ + "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/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", + "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 25dc0956..00000000 --- a/discord/discord.ts +++ /dev/null @@ -1,235 +0,0 @@ -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 { Logger } from "../logging/logger.ts"; - -export * from "https://deno.land/x/discordeno@13.0.0/mod.ts"; - -export interface DiscordInitOpts { - token: string; - intents: any[]; - botId: bigint|number; - withCache?: boolean; -} - -export class Discord { - protected static bot: any; - 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 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); - } - if('intents' in opts) this.intents = opts.intents; - 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); - }, - 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); - }, - guildLoaded(_bot, data) { - EventDispatcher.dispatch('GuildLoaded', data); - }, - 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('InteractionCreate', 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); - }, - voiceChannelLeave(_bot, voiceState, guild, channel) { - EventDispatcher.dispatch('VoiceChannelLeave', { voiceState: voiceState, guild: guild, channel: channel }); - }, - 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 - if(opts.withCache === true) { - const bot = enableCachePlugin(baseBot); - enableCacheSweepers(bot); - Discord.bot = bot; - } else { - Discord.bot = baseBot; - } - } - - /** - * Start the bot and connect to the Discord gateway - * - * @returns Promise - */ - public async start(): Promise { - await startBot(Discord.bot); - } -} diff --git a/discord/event-dispatcher.ts b/discord/event-dispatcher.ts deleted file mode 100644 index e4027e52..00000000 --- a/discord/event-dispatcher.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Logger } from "../logging/logger.ts"; - -interface EventConfig { - name: string; - handler: string; -} - -export interface Event { - execute(opts: any): Promise; -} - -export class EventDispatcher { - private static list: EventConfig[] = []; - private static handlers: any = {}; - - /** - * Return the complete list of events - * - * @returns EventConfig[] - */ - public static getEvents() { return EventDispatcher.list; } - - /** - * Find an Event by name - * - * @param name - * @returns IEvent|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 - * - * @param 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`) - } 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 - */ - 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); - } - } -} diff --git a/discord/interaction-dispatcher.ts b/discord/interaction-dispatcher.ts deleted file mode 100644 index bcd506da..00000000 --- a/discord/interaction-dispatcher.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { ApplicationCommandOption } from "https://deno.land/x/discordeno@13.0.0/mod.ts"; -import { Discord } from "./discord.ts"; -import { Logger } from "../logging/logger.ts"; - -interface InteractionConfig { - name: string; - description: string; - type: any; - options?: ApplicationCommandOption[]; - handler: string; -} - -export interface Interaction { - execute(): Promise; -} - -export class InteractionDispatcher { - 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://${Deno.cwd()}/src/interactions/${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.warning(`Interaction "${interaction}" does not exist! (did you register it?)`); - return; - } - - // Create an instance of the handler - const controller = new InteractionDispatcher.handlers[handler.handler][`${interaction[0].toUpperCase() + interaction.slice(1)}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); - } - } -} 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..87e79a01 --- /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":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 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..96b543ab --- /dev/null +++ b/docs/~/Controller.html @@ -0,0 +1,813 @@ + + + + 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 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..bacbea62 --- /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[] + +
+ + + + +
+
+ + + + + + + + + + +
+
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 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..040d9b32 --- /dev/null +++ b/docs/~/Time.html @@ -0,0 +1,983 @@ + + + + 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 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..d9ed30e7 --- /dev/null +++ b/docs/~/TimeString.html @@ -0,0 +1,370 @@ + + + + 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 new file mode 100644 index 00000000..3c00a4e5 --- /dev/null +++ b/docs/~/TimeStringSeconds.html @@ -0,0 +1,370 @@ + + + + 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 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..e6558519 --- /dev/null +++ b/docs/~/Websocket.html @@ -0,0 +1,571 @@ + + + + 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 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/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, +} diff --git a/error/raise.ts b/error/raise.ts new file mode 100644 index 00000000..0362b23b --- /dev/null +++ b/error/raise.ts @@ -0,0 +1,60 @@ +/** + * 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", +): never { + // 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; + } + + // 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/file.ts b/filesystem/file.ts new file mode 100644 index 00000000..9cb4d116 --- /dev/null +++ b/filesystem/file.ts @@ -0,0 +1,38 @@ +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); + } + + 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 new file mode 100644 index 00000000..a92b4d30 --- /dev/null +++ b/filesystem/folder.ts @@ -0,0 +1,36 @@ +import { Logger } from "../core/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); + return target.isDirectory; + } catch (e) { + if (e instanceof Deno.errors.NotFound) return false; + 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); + } +} diff --git a/logging/logger.ts b/logging/logger.ts deleted file mode 100644 index 74279b16..00000000 --- a/logging/logger.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Time } from "../common/time.ts"; -import { Configure } from "../common/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}`); } - - /** - * 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 { - // 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')) { - try { - let output = `[${now}] ERROR > ${message}`; - 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}`; - console.error(output); - } - - /** - * Write a debug message to the console - * Only shows up when the "DEBUG" env is set to truthy - * - * @param 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}`); - } - - /** - * Write a stacktrace to the console - * - * @param stacktrace The stacktrace - * @returns void - */ - public static trace(stacktrace: any): void { - Logger.warning('Use of Logger#stack is deprecated, please pass trace to Logger#error instead.'); - console.error(stacktrace); - } - - /** - * 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) - * - * @returns string The formatted time - */ - private static time(): string { - return new Time().format(Configure.get('logger.timeformat', 'yyyy/MM/dd HH:mm:ss')); - } -} diff --git a/mod.ts b/mod.ts index b3fb9148..c0a32f38 100644 --- a/mod.ts +++ b/mod.ts @@ -1,38 +1,68 @@ -export { Configure } from "./common/configure.ts"; -export { cron } from "./common/cron.ts"; -export { env } from "./common/env.ts"; -export { Time } from "./common/time.ts"; - +/** + * 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 { - Discord, - InteractionResponseTypes, - ApplicationCommandTypes, - ApplicationCommandOptionTypes -} from "./discord/discord.ts"; -export type { DiscordEmbed, Intents } from "./discord/discord.ts"; -export { EventDispatcher } from "./discord/event-dispatcher.ts"; -export { InteractionDispatcher } from "./discord/interaction-dispatcher.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 { File } from "./filesystem/file.ts"; +export { Folder } from "./filesystem/folder.ts"; -export { Logger } from "./logging/logger.ts"; -export { Queue, Scheduler } from "./queue/queue.ts"; +/** + * Queue + */ +export { Queue } from "./queue/queue.ts"; -export { Hash, Algorithms } from "./security/hash.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 { CheckSource } from "./util/check-source.ts"; -export { tokenizer } from "./util/tokenizer.ts"; -export { lcfirst } from "./util/lcfirst.ts"; -export { ucfirst } from "./util/ucfirst.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 { 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 { 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"; +/** + * Webserver + */ +export * from "./webserver/mod.ts"; -export { Websocket } from "./websocket/websocket.ts"; -export { Events } from "./websocket/events.ts"; +/** + * Websocket + */ +export * from "./websocket/mod.ts"; diff --git a/queue/queue.ts b/queue/queue.ts index c5e93a1f..8cfc05e0 100644 --- a/queue/queue.ts +++ b/queue/queue.ts @@ -1,7 +1,8 @@ -import { Logger } from "../logging/logger.ts"; +import { Logger } from "../core/logger.ts"; interface QueueItem { weight?: number; + // deno-lint-ignore no-explicit-any -- Any arbitrary data may be used data: any; } @@ -29,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. @@ -44,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 @@ -59,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]; @@ -72,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 @@ -81,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(item.hasOwnProperty('weight')) { - 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(item.hasOwnProperty('weight')) { - 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(!item.hasOwnProperty('weight')) { - 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); @@ -118,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!"); } } @@ -131,16 +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) { - if(!queued.data.hasOwnProperty(key)) return false; - if(queued.data[key] !== item.data[key]) return false; + 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; } return true; }); - return typeof match !== 'undefined'; + return typeof match !== "undefined"; } /** @@ -148,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 87342388..fd35b37c 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", } /** @@ -48,18 +48,50 @@ export const INSECURE_ALGORITHMS: string[] = [ ]; export class Hash { - private result: any; + private result!: ArrayBuffer; constructor( private input: string, 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(''); + 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..c372c782 100644 --- a/security/password.ts +++ b/security/password.ts @@ -15,46 +15,49 @@ 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", } -// 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 -} + allowInsecure: false, +}; /** * 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,18 +71,24 @@ 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.'); + 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 @@ -91,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 @@ -99,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 @@ -118,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 c37bf56b..65a20555 100644 --- a/security/random.ts +++ b/security/random.ts @@ -1,6 +1,15 @@ export class Random { /** - * Generate random bytes + * Generate random bytes. + * These bytes are generated using the Web Crypto API, this is cryptographically secure. + * + * @example Basic Usage + * ```ts + * import { Random } 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 @@ -12,13 +21,93 @@ export class Random { } /** - * Generate a random string + * Generate a random string. + * These strings are generated using the Web Crypto API, this is cryptographically secure. + * + * @example Basic Usage + * ```ts + * import { Random } 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 */ 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(""); + } + + /** + * Inclusively generate a random integer between min and max. + * 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 { 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); + * ``` + * + * @example Cryptographically secure + * ```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); + * ``` + * + * @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! + * + * @example Basic Usage + * ```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); + * ``` + * + * @example Cryptographically secure + * ```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); + * ``` + * + * @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; } } diff --git a/tests/common/configure.test.ts b/tests/common/configure.test.ts new file mode 100644 index 00000000..e7766797 --- /dev/null +++ b/tests/common/configure.test.ts @@ -0,0 +1,28 @@ +import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; +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"); + + // Make sure consume works as intended + 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); + + // 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 + assertEquals(Configure.get("test4", "default value"), "default value"); + assertEquals(Configure.get("test5", "default value"), "default value"); +}); diff --git a/tests/common/configure.ts b/tests/common/configure.ts deleted file mode 100644 index 62372443..00000000 --- a/tests/common/configure.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { Configure } from "../../common/configure.ts"; - -Deno.test("Configure Test", async (t) => { - // Add a test variable and test against it - 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); - - // Add a new test variable and immediately try to delete it - Configure.set('test2', 'chomp'); - Configure.delete('test2'); - assertEquals(Configure.check('test2'), false); - - // Make sure clearing works - Configure.set('test3', 'chomp'); - Configure.clear(); - 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'); -}); diff --git a/tests/error/raise.test.ts b/tests/error/raise.test.ts new file mode 100644 index 00000000..266dec26 --- /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"); +}); diff --git a/tests/queue/queue.test.ts b/tests/queue/queue.test.ts new file mode 100644 index 00000000..47a481d3 --- /dev/null +++ b/tests/queue/queue.test.ts @@ -0,0 +1,112 @@ +import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; +import { Queue, Scheduler } from "../../queue/queue.ts"; + +Deno.test("Queue Test", async (t) => { + await t.step("Common", () => { + // Create our queue + const queue = new Queue(Scheduler.FIFO); + + // Test isEmpty and count without items + assertEquals(queue.isEmpty, true); + assertEquals(queue.count, 0); + + // Test next and peek on an empty queue + assertEquals(queue.peek, null); + 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" } }); + + // Test isEmpty and count with items + assertEquals(queue.isEmpty, false); + assertEquals(queue.count, 4); + + // Make sure clearing works + 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" } }); + + // Make sure peeking works without removal + assertEquals(queue.peek, { data: { job: "test1" } }); + assertEquals(queue.count, 4); + + // Make sure next works with removal + assertEquals(queue.next, { data: { job: "test1" } }); + assertEquals(queue.count, 3); + 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); + }); + + await t.step("LIFO Scheduler", () => { + // Create our queue + 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" } }); + + // Make sure peeking works without removal + assertEquals(queue.peek, { data: { job: "test4" } }); + assertEquals(queue.count, 4); + + // Make sure next works with removal + assertEquals(queue.next, { data: { job: "test4" } }); + assertEquals(queue.count, 3); + 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); + }); + + await t.step("WEIGHTED Scheduler", () => { + // Create our queue + 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" } }); + + // Make sure peeking works without removal + 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.count, 5); + 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); + + // Make sure we didn't add "weightless" items + assertEquals(queue.contains({ data: { job: "test6" } }), false); + }); +}); diff --git a/tests/queue/queue.ts b/tests/queue/queue.ts deleted file mode 100644 index 5f2c9eef..00000000 --- a/tests/queue/queue.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { assertEquals } from "https://deno.land/std@0.152.0/testing/asserts.ts"; -import { Queue, Scheduler } from "../../queue/queue.ts"; - -Deno.test("Queue Test", async (t) => { - await t.step("Common", () => { - // Create our queue - const queue = new Queue(Scheduler.FIFO); - - // Test isEmpty and count without items - assertEquals(queue.isEmpty, true); - assertEquals(queue.count, 0); - - // Test next and peek on an empty queue - assertEquals(queue.peek, null); - 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', } }); - - // Test isEmpty and count with items - assertEquals(queue.isEmpty, false); - assertEquals(queue.count, 4); - - // Make sure clearing works - 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', } }); - - // Make sure peeking works without removal - assertEquals(queue.peek, { data: { job: 'test1', } }); - assertEquals(queue.count, 4); - - // Make sure next works with removal - assertEquals(queue.next, { data: { job: 'test1', } }); - assertEquals(queue.count, 3); - 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); - }); - - await t.step("LIFO Scheduler", () => { - // Create our queue - 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', } }); - - // Make sure peeking works without removal - assertEquals(queue.peek, { data: { job: 'test4', } }); - assertEquals(queue.count, 4); - - // Make sure next works with removal - assertEquals(queue.next, { data: { job: 'test4', } }); - assertEquals(queue.count, 3); - 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); - }); - - await t.step("WEIGHTED Scheduler", () => { - // Create our queue - 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', } }); - - // Make sure peeking works without removal - 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.count, 5); - 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); - - // Make sure we didn't add "weightless" items - assertEquals(queue.contains({ data: { job: 'test6', } }), false); - }); -}) diff --git a/tests/util/contract.test.ts b/tests/util/contract.test.ts new file mode 100644 index 00000000..eff1fd75 --- /dev/null +++ b/tests/util/contract.test.ts @@ -0,0 +1,58 @@ +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", () => { + // 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")); + }); + + 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 empty + assert(() => Contract.requireNotEmpty(0)); + assert(() => Contract.requireNotEmpty("blabla")); + 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/tests/util/inflector.test.ts b/tests/util/inflector.test.ts new file mode 100644 index 00000000..6a80edba --- /dev/null +++ b/tests/util/inflector.test.ts @@ -0,0 +1,28 @@ +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) => { + 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"); + }); +}); diff --git a/tests/util/name-of.test.ts b/tests/util/name-of.test.ts new file mode 100644 index 00000000..38995d1a --- /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", () => { + const testArgument = "blabla"; + assertEquals(nameOf({ testArgument }), "testArgument"); + assertNotEquals(nameOf({ testArgument }), "testargument"); +}); diff --git a/tests/util/text.test.ts b/tests/util/text.test.ts new file mode 100644 index 00000000..73fd12fc --- /dev/null +++ b/tests/util/text.test.ts @@ -0,0 +1,29 @@ +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) => { + 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("<"), "<"); + 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/util/check-source.ts b/util/check-source.ts deleted file mode 100644 index 076ffc1e..00000000 --- a/util/check-source.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Logger } from "../logging/logger.ts"; - -export interface ExclusionConfig { - directories?: string[]; - files?: string[]; -} - -export class CheckSource { - private files: string[] = []; - private errors = 0; - - constructor( - private readonly path: string, - private readonly exclusions: ExclusionConfig = { directories: [], files: [] } - ) {} - - public async run(): Promise { - // Get list of files - await this.getFiles(this.path); - - // Checkk all files found - Logger.info(`Checking "${this.files.length}" files...`); - 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.`); - Deno.exit(1); - } - Logger.info(`Finished checking files!`); - Deno.exit(0); - } - - /** - * Recursively can all files in the given path - * Ignore directories and files given in our exclusions - * - * @param path - */ - 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)) { - 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)) { - Logger.debug(`Skipping excluded file "${path}/${entry.name}"...`); - continue; - } - if(!this.isTs(entry.name)) { - Logger.debug(`Skipping non-ts file...`); - continue; - } - Logger.debug(`Found file "${path}/${entry.name}"...`); - this.addFile(`${path}/${entry.name}`); - } - } - } - - /** - * Add file to array of files - * - * @param path - */ - private addFile(path: string) { - if(this.files.includes(path)) return; - this.files.push(path); - } - - /** - * Check all files found - */ - private async checkFiles() { - for await(const file of this.files) { - try { - await import(`file://${Deno.cwd()}/${file}`); - } catch(e) { - Logger.error(`Check for "${Deno.cwd()}/${file}" failed: ${e.message}`, e.stack); - this.errors++; - } - } - } - - /** - * 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/util/lcfirst.ts b/util/lcfirst.ts deleted file mode 100644 index 4fd59743..00000000 --- a/util/lcfirst.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function lcfirst(input: string): string { - return input.charAt(0).toLowerCase() + input.slice(1); -} 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/ucfirst.ts b/util/ucfirst.ts deleted file mode 100644 index 421ce516..00000000 --- a/util/ucfirst.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function ucfirst(input: string): string { - return input.charAt(0).toUpperCase() + input.slice(1); -} diff --git a/utility/check-source.ts b/utility/check-source.ts new file mode 100644 index 00000000..704e8670 --- /dev/null +++ b/utility/check-source.ts @@ -0,0 +1,123 @@ +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. + * 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; + + constructor( + private readonly paths: string[], + private readonly exclusions: ExclusionConfig = { directories: [], files: [] }, + ) {} + + public async run(): Promise { + // 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...`); + 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.`, + ); + Deno.exit(1); + } + Logger.info(`Finished checking files without errors!`); + Deno.exit(0); + } + + /** + * Recursively can all files in the given path + * Ignore directories and files given in our exclusions + * + * @param path + */ + 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)) { + 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)) { + Logger.debug(`Skipping excluded file "${path}/${entry.name}"...`); + continue; + } + if (new File(`${path}/${entry.name}`).ext() !== "ts") { + Logger.debug(`Skipping non-ts file...`); + continue; + } + Logger.debug(`Found file "${path}/${entry.name}"...`); + this.addFile(`${path}/${entry.name}`); + } + } + } + + /** + * Add file to array of files + * + * @param path + */ + private addFile(path: string) { + if (this.files.includes(path)) return; + this.files.push(path); + } + + /** + * Check all files found + */ + private async checkFiles() { + for await (const file of this.files) { + try { + await import(`file://${Deno.cwd()}/${file}`); + } catch (e) { + Logger.error(`Check for "${Deno.cwd()}/${file}" failed: ${e.message}`, e.stack); + this.errors++; + } + } + } +} diff --git a/utility/contract.ts b/utility/contract.ts new file mode 100644 index 00000000..5cdabdbb --- /dev/null +++ b/utility/contract.ts @@ -0,0 +1,121 @@ +import { raise } from "../error/raise.ts"; +import { nameOf } from "../mod.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|never { + 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"; + * + * 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: unknown, argumentName: string): void|never { + 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"); + } + + /** + * 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"); + } +} diff --git a/utility/cron.ts b/utility/cron.ts new file mode 100644 index 00000000..ea5e3560 --- /dev/null +++ b/utility/cron.ts @@ -0,0 +1 @@ +export { Cron } from "https://deno.land/x/croner@5.3.4/src/croner.js"; diff --git a/utility/empty.ts b/utility/empty.ts new file mode 100644 index 00000000..f5b1ff04 --- /dev/null +++ b/utility/empty.ts @@ -0,0 +1,12 @@ +/** + * Check whether the input is set and empty + * + * @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; +} 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]}` +} diff --git a/utility/inflector.ts b/utility/inflector.ts new file mode 100644 index 00000000..32b6e0e3 --- /dev/null +++ b/utility/inflector.ts @@ -0,0 +1,65 @@ +/** + * 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); + } + + /** + * 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 this + .humanize(input, delimiter) + .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.) + * + * @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] = this.ucfirst(tokens[i]); + } + + // Join tokens into a string and return + return tokens.join(" "); + } +} diff --git a/utility/name-of.ts b/utility/name-of.ts new file mode 100644 index 00000000..fd6388a2 --- /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]; diff --git a/utility/text.ts b/utility/text.ts new file mode 100644 index 00000000..7545d419 --- /dev/null +++ b/utility/text.ts @@ -0,0 +1,42 @@ +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) { + const ret = tokens.splice(0, limit); + ret.push(tokens.join(" ")); + return ret; + } + + 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)); + } +} diff --git a/util/time-string.ts b/utility/time-string.ts similarity index 72% rename from util/time-string.ts rename to utility/time-string.ts index 3a965292..942182d0 100644 --- a/util/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": @@ -69,15 +69,24 @@ 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 */ -export function T(strIn: TemplateStringsArray, ...parts: any[]) { - const str = String.raw(strIn, parts).toLowerCase().replace(/\s/g, ''); +// 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 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)); @@ -88,10 +97,18 @@ export function T(strIn: TemplateStringsArray, ...parts: any[]) { /** * 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 */ -export function _T(strIn: TemplateStringsArray, ...parts: any[]) { - return Math.round(T(strIn, parts) / 1000); +// deno-lint-ignore no-explicit-any -- TODO +export function TimeStringSeconds(strIn: TemplateStringsArray, ...parts: any[]): number { + return Math.round(TimeString(strIn, parts) / 1000); } diff --git a/utility/time.ts b/utility/time.ts new file mode 100644 index 00000000..22526246 --- /dev/null +++ b/utility/time.ts @@ -0,0 +1,62 @@ +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"; + +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 constructor(time: string | undefined = undefined) { + this.time = timets(time).tz(Deno.env.get("TZ")!).t; + } + + public format(format: string) { + return formatter(this.time, format); + } + + public midnight() { + this.time.setHours(0, 0, 0, 0); + return this; + } + + public add(input: string) { + this.time.setMilliseconds(this.time.getMilliseconds() + TimeString`${input}`); + return this; + } + + public addDay(days: number = 1) { + this.time.setDate(this.time.getDate() + days); + return this; + } + + public addWeek(weeks: number = 1) { + this.time.setDate(this.time.getDate() + (weeks * 7)); + return this; + } +} diff --git a/webserver/controller/component.ts b/webserver/controller/component.ts new file mode 100644 index 00000000..84a65b0d --- /dev/null +++ b/webserver/controller/component.ts @@ -0,0 +1,12 @@ +import { Controller } from "./controller.ts"; + +export class Component { + public constructor( + 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 8b4a23c2..cc48ba8b 100644 --- a/webserver/controller/controller.ts +++ b/webserver/controller/controller.ts @@ -1,20 +1,101 @@ -import { handlebarsEngine } from "https://raw.githubusercontent.com/FinlayDaG33k/view-engine/patch-1/mod.ts"; -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"; +import { Request } from "../http/request.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"; + +export interface ViewVariable { + [key: string]: string | number | unknown; +} export class Controller { - protected name = '' - protected action = ''; - protected vars: any = {}; - protected status = 200; - protected body = ''; - protected type = 'text/html'; + private static readonly _templateDir = `./src/templates`; + private static readonly _componentDir = `file:///${Deno.cwd()}/src/controller/component`; + private _response: ResponseBuilder = new ResponseBuilder(); + private _vars: ViewVariable = {}; + + /** + * Set the 'Content-Type' header + * + * @deprecated Please use "Controller.getResponse().withType()" instead. + * @param value + */ + // @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.', + ); + this.getResponse().withHeader("Content-Type", value); + } constructor( - name: string, - action: string = 'index' + protected readonly request: Request, ) { - this.name = name; - this.action = action; + } + + /** + * 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 + * + * @protected + */ + protected getRequest(): Request { + return this.request; + } + + /** + * Get the response object for this controller + * + * @protected + */ + protected getResponse(): ResponseBuilder { + return this._response; + } + + 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`); + // TODO: Fix index signature + // @ts-ignore -- + 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`); + + // 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.`); + } + + // Add the component to the registry + 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; } /** @@ -23,7 +104,9 @@ export class Controller { * @param key * @param value */ - protected set(key: string, value: any) { this.vars[key] = value; } + protected set(key: string, value: string | number | unknown) { + this._vars[key] = value; + } /** * Render the page output @@ -32,53 +115,40 @@ export class Controller { * @returns Promise */ public async render(): Promise { - switch(this.type) { - case 'application/json': - this.body = JSON.stringify(this.vars['data']); + let body: string | Uint8Array = ""; + const canCompress = true; + switch (this.getResponse().getHeaderLine("Content-Type").toLowerCase()) { + case "application/json": { + body = JSON.stringify(this._vars["data"]); break; - case 'text/plain': - this.body = this.vars['message']; + } + case "text/plain": { + body = this._vars["message"] as string; + 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 : ''; break; - case 'text/html': - default: - this.body = await this.handlebars(); + } + case "application/octet-stream": { + body = this._vars["data"] as Uint8Array; + break; + } } - } - /** - * Render Handlebars templates - * - * @returns Promise - */ - private async handlebars(): Promise { - // Get our template location - const path = `./src/templates/${this.name[0].toLowerCase() + this.name.slice(1)}/${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); - return; + // 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 && 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`); + this.getResponse().withHeader("Content-Encoding", "br"); } - // Read our template - const template = await Deno.readTextFile(`./src/templates/${this.name[0].toLowerCase() + this.name.slice(1)}/${this.action}.hbs`); - - // Let the engine render - return handlebarsEngine(template, this.vars); - } - - public response() { - return new Response( - this.body, - { - status: this.status, - headers: { - 'content-type': this.type, - 'Access-Control-Allow-Origin': '*' - } - } - ); + // Set our final body + this.getResponse().withBody(body); } } 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/http/mod.ts b/webserver/http/mod.ts new file mode 100644 index 00000000..4a93eacf --- /dev/null +++ b/webserver/http/mod.ts @@ -0,0 +1,2 @@ +export * from "./request.ts"; +export * from "./status-codes.ts"; diff --git a/webserver/http/request.ts b/webserver/http/request.ts new file mode 100644 index 00000000..2487d529 --- /dev/null +++ b/webserver/http/request.ts @@ -0,0 +1,70 @@ +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, + private readonly method: string, + private readonly route: Route, + 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(): 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]; + return null; + } + + 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 new file mode 100644 index 00000000..a6e36f30 --- /dev/null +++ b/webserver/http/response-builder.ts @@ -0,0 +1,165 @@ +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; + private _body: string | Uint8Array = ""; + + 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 the response MIME + * + * @param 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 { + this._status = status; + return this; + } + + /** + * Set our response body. + * + * @param body + */ + public withBody(body: string|Uint8Array): ResponseBuilder { + this._body = body; + 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. + */ + public build(): Response { + // 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, + { + status: this._status, + headers: headers, + }, + ); + } +} diff --git a/webserver/http/status-codes.ts b/webserver/http/status-codes.ts new file mode 100644 index 00000000..f66ea45a --- /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/mod.ts b/webserver/mod.ts new file mode 100644 index 00000000..265235a2 --- /dev/null +++ b/webserver/mod.ts @@ -0,0 +1,4 @@ +export * from "./controller/mod.ts"; +export * from "./http/mod.ts"; +export * from "./routing/mod.ts"; +export * from "./webserver.ts"; diff --git a/webserver/pathToRegexp.ts b/webserver/pathToRegexp.ts index 57e045c2..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,19 @@ 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 = ""; @@ -293,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`, ); } @@ -308,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}"`, ); } @@ -323,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}"`, ); } @@ -366,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

; /** @@ -374,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); @@ -387,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; @@ -405,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 { @@ -464,7 +465,7 @@ function regexpToRegexp(path: RegExp, keys?: Key[]): RegExp { prefix: "", suffix: "", modifier: "", - pattern: "" + pattern: "", }); execResult = groupsRegex.exec(path.source); } @@ -478,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)); } @@ -490,7 +491,7 @@ function arrayToRegexp( function stringToRegexp( path: string, keys?: Key[], - options?: TokensToRegexpOptions & ParseOptions + options?: TokensToRegexpOptions & ParseOptions, ) { return tokensToRegexp(parse(path, options), keys, options); } @@ -532,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 || "/#?")}]`; @@ -577,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}))?`; @@ -610,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 new file mode 100644 index 00000000..2e80affa --- /dev/null +++ b/webserver/registry/registry.ts @@ -0,0 +1,35 @@ +interface RegistryItem { + [key: string]: any; +} + +export class Registry { + private static _items: RegistryItem = {}; + + /** + * Add an item to the registry + * + * @param name + * @param module + */ + public static add(name: string, module: any): void { + Registry._items[name] = module; + } + + /** + * Get an item from the registry + * + * @param name + */ + public static get(name: string): any | 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/renderers/handlebars.ts b/webserver/renderers/handlebars.ts new file mode 100644 index 00000000..0d537fcf --- /dev/null +++ b/webserver/renderers/handlebars.ts @@ -0,0 +1,46 @@ +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 = {}; + + 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) ?? raise("Could not load template"); + + // 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; + + // 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) { + throw new Error(`Could not render handlebars template: Could not read template at "${path}"`, e.stack); + } + + // Read and our template + return await Deno.readTextFile(path); + } +} 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"; 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/webserver/routing/route.ts b/webserver/routing/route.ts new file mode 100644 index 00000000..071b665d --- /dev/null +++ b/webserver/routing/route.ts @@ -0,0 +1,25 @@ +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 8675164e..435f193e 100644 --- a/webserver/routing/router.ts +++ b/webserver/routing/router.ts @@ -1,77 +1,163 @@ 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 { 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 "../../error/raise.ts"; interface Route { path: string; controller: string; action: string; - method: string; -} - -export interface RouteArgs { - route: Route; - body: string; - params: any; - auth?: string; + method?: string; } export class Router { - private static routes: Route[] = []; - public static getRoutes() { return Router.routes; } + private static readonly _controllerDir = `file://${Deno.cwd()}/src/controller`; + private static routes: ChompRoute[] = []; + public static getRoutes() { + return Router.routes; + } /** * Match the controller and action to a route * * @param request */ - public async 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 .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]; // Loop over each route // 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) { - if(route.method !== request.method) continue; + for (const route of Router.routes) { + if (route.getMethod() !== request.method) continue; // Make sure we have a matching route - const matches = pathToRegexp(route.path).exec(path); - if(matches) return { - route: route, - path: path - }; + const matches = pathToRegexp(route.getPath()).exec(path); + if (matches) { + return { + route: route, + path: path, + }; + } } } /** * Execute the requested controller action * - * @param args + * @param request + * @param clientIp * @returns Promise */ - public async execute(args: RouteArgs): Promise { - // 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); + 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); + if (!route || !route.route) { + return new Response( + "The requested page could not be found.", + { + status: StatusCodes.NOT_FOUND, + headers: { + "Content-Type": "text/plain", + }, + }, + ); + } - // Render the body - await controller.render(); + // Build our Request object + const req = new ChompRequest( + request.url, + request.method, + route.route, + request.headers, + await Router.getBody(request), + Router.getParams(route.route, route.path), + Router.getQuery(request.url), + Router.getAuth(request), + clientIp, + ); + + // Import and cache controller file if need be + if (!Registry.has(req.getRoute().getController())) { + 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) { + Logger.error(`Could not import "${req.getRoute().getController()}": ${e.message}`, e.stack); + return new Response( + "Internal Server Error", + { + status: 500, + headers: { + "content-type": "text/plain", + }, + }, + ); + } + } - // Return our response - return controller.response(); + // 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 controller = new module[`${req.getRoute().getController()}Controller`](req); + + // Run the controller's initializer + await controller.initialize(); + + // Execute our action + await controller[req.getRoute().getAction()](); + + // Render the body + await controller.render(); + + // Return our response + return controller.getResponse().build(); + } catch (e) { + Logger.error(`Could not execute "${req.getRoute().getController()}": ${e.message}`, e.stack); + return new Response( + "An Internal Server Error Occurred", + { + status: 500, + headers: { + "Content-Type": "text/plain", + }, + }, + ); + } } /** @@ -79,30 +165,49 @@ export class Router { * * @param route * @param path - * @returns Promise<{ [key: string]: string }> + * @returns RequestParameters */ - public async getParams(route: Route, path: string): Promise<{ [key: string]: string }> { - const keys: any[] = []; - const r = pathToRegexp(route.path, keys).exec(path) || []; - + 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 + * + * @param path + * @returns QueryParameters + */ + public static getQuery(path: string): QueryParameters { + const params = new URLSearchParams(path.split("?")[1]); + return Object.fromEntries(params.entries()); + } + /** * Get the body from the request * * @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 ''; + if (request.body === null) return ""; // Create a reader 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); @@ -114,20 +219,27 @@ 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 - const header = request.headers.get("authorization"); - return header ?? ''; + return request.headers.get("authorization") ?? ""; } /** - * Add a route + * Add a route. + * Defaults to 'GET' * * @param route * @returns void */ public static add(route: Route): void { - Router.routes.push(route); + 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 5ec9ce7b..bf66bf45 100644 --- a/webserver/webserver.ts +++ b/webserver/webserver.ts @@ -1,13 +1,13 @@ -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"; export class Webserver { - private server: any = null; - private port: number = 0; - private router: Router = new Router(); + private server: Deno.Listener | null = null; - constructor(port: number = 80) { - this.port = port; + constructor( + private readonly port: number = 80, + ) { } public async start() { @@ -16,42 +16,41 @@ export class Webserver { // Serve connections for await (const conn of this.server) { + // @ts-ignore Left intentionally without await this.serve(conn); } } 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 - 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 { - const routing = await this.router.route(request.request); - if(!routing || !routing.route) { - return new Response( - 'The requested page could not be found.', - { - status: 404, - headers: { - 'content-type': 'text/plain', - 'Access-Control-Allow-Origin': '*' - } - } - ); - } - 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) - }); - if(!response) throw Error('Response was empty'); + // 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('Internal server error', {status: 500})); + 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 80321461..4f8fdb31 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 { Logger } from "../core/logger.ts"; +import { Configure } from "../core/configure.ts"; export class Authenticator { /** @@ -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 35463e5d..a91c4a6a 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; @@ -7,8 +7,11 @@ 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; } + public static getEvents() { + return Events.list; + } public static getHandler(name: string) { return Events.list.find((event: IEvent) => event.name === name); @@ -17,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; } @@ -26,18 +29,19 @@ 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); - 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/mod.ts b/websocket/mod.ts new file mode 100644 index 00000000..c3bc65ea --- /dev/null +++ b/websocket/mod.ts @@ -0,0 +1,3 @@ +export * from "./authenticator.ts"; +export * from "./events.ts"; +export * from "./websocket.ts"; diff --git a/websocket/websocket.ts b/websocket/websocket.ts index 2464e9c7..393ecb09 100644 --- a/websocket/websocket.ts +++ b/websocket/websocket.ts @@ -1,13 +1,13 @@ -import { WebSocketServer, WebSocketAcceptedClient } from "https://deno.land/x/websocket@v0.1.3/mod.ts"; -import { Logger } from "../logging/logger.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"; -import { Configure } from "../common/configure.ts"; +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,67 +15,72 @@ 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)); }); } - 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; + 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) { - 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 - let data = JSON.parse(message); + const data = JSON.parse(message); + // Get the Event let event = data.event; - let tokens = []; - for(let token of event.split('_')) { + const tokens = []; + 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); } } - 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?)`); + 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`); @@ -85,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); } }