diff --git a/src/bundle/start.ts b/src/bundle/start.ts index c14487a9..5c2e28bd 100644 --- a/src/bundle/start.ts +++ b/src/bundle/start.ts @@ -18,7 +18,6 @@ // process.env.MONGOMS_DEBUG = "true"; import moduleAlias from "module-alias"; - moduleAlias(__dirname + "../../../package.json"); import "reflect-metadata"; diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index b79cc5d4..a83f4db4 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -566,7 +566,7 @@ export class Channel extends BaseClass { let userPerms = new Permissions(new BitField(0).add(roles.map(r => r.permissions))); // TODO: do we want to have an instance-wide opt out of this behavior? It would just be an extra if statement here - if (userPerms.has(Permissions.FLAGS.ADMINISTRATOR)) return true; + if (userPerms.has(Permissions.FLAGS.ADMINISTRATOR)) return userPerms; // apply channel overrides if (this.permission_overwrites) { diff --git a/src/util/util/Array.ts b/src/util/util/Array.ts deleted file mode 100644 index 082ac307..00000000 --- a/src/util/util/Array.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -// TODO: remove this function. - -export function containsAll(arr: unknown[], target: unknown[]) { - return target.every((v) => arr.includes(v)); -} - -/* https://stackoverflow.com/a/50636286 */ -export function partition(array: T[], filter: (elem: T) => boolean) { - const pass: T[] = [], - fail: T[] = []; - array.forEach((e) => (filter(e) ? pass : fail).push(e)); - return [pass, fail]; -} diff --git a/src/util/util/Url.ts b/src/util/util/Url.ts deleted file mode 100644 index a2349126..00000000 --- a/src/util/util/Url.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Normalize a URL by: - * - Removing trailing slashes (except root path) - * - Sorting query params alphabetically - * - Removing empty query strings - * - Removing fragments - */ -export function normalizeUrl(input: string): string { - try { - const u = new URL(input); - // Remove fragment - u.hash = ""; - // Normalize pathname - remove trailing slash except for root "/" - if (u.pathname !== "/" && u.pathname.endsWith("/")) { - u.pathname = u.pathname.slice(0, -1); - } - // Normalize query params: sort by key - if (u.search) { - const params = Array.from(u.searchParams.entries()); - params.sort(([a], [b]) => a.localeCompare(b)); - u.search = params.length - ? "?" + params.map(([k, v]) => `${k}=${v}`).join("&") - : ""; - } else { - // Ensure no empty search string - u.search = ""; - } - return u.toString(); - } catch (e) { - return input; - } -} diff --git a/src/util/util/extensions/Array.ts b/src/util/util/extensions/Array.ts new file mode 100644 index 00000000..84180347 --- /dev/null +++ b/src/util/util/extensions/Array.ts @@ -0,0 +1,58 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2025 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +declare global { + interface Array { + containsAll(target: T[]): boolean; + partition(filter: (elem: T) => boolean): [T[], T[]]; + single(filter: (elem: T) => boolean): T | null; + } +} + +export function containsAll(arr: T[], target: T[]) { + return target.every((v) => arr.includes(v)); +} + +/* https://stackoverflow.com/a/50636286 */ +export function partition(array: T[], filter: (elem: T) => boolean): [T[], T[]] { + const pass: T[] = [], + fail: T[] = []; + array.forEach((e) => (filter(e) ? pass : fail).push(e)); + return [pass, fail]; +} + +export function single(array: T[], filter: (elem: T) => boolean): T | null { + const results = array.filter(filter); + if (results.length > 1) throw new Error("Array contains more than one matching element"); + if (results.length === 0) return null; + return results[0]; +} + +// register extensions +if (!Array.prototype.containsAll) + Array.prototype.containsAll = function (this: T[], target: T[]) { + return containsAll(this, target); + }; +if (!Array.prototype.partition) + Array.prototype.partition = function (this: T[], filter: (elem: T) => boolean) { + return partition(this, filter); + }; +if (!Array.prototype.single) + Array.prototype.single = function (this: T[], filter: (elem: T) => boolean) { + return single(this, filter); + }; diff --git a/src/util/util/extensions/Url.d.ts b/src/util/util/extensions/Url.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/util/util/extensions/Url.ts b/src/util/util/extensions/Url.ts new file mode 100644 index 00000000..c0f07b37 --- /dev/null +++ b/src/util/util/extensions/Url.ts @@ -0,0 +1,60 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2025 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +declare module "url" { + interface URL { + normalize(): string; + } +} + +/** + * Normalize a URL by: + * - Removing trailing slashes (except root path) + * - Sorting query params alphabetically + * - Removing empty query strings + * - Removing fragments + */ +export function normalizeUrl(input: string): string { + try { + const u = new URL(input); + // Remove fragment + u.hash = ""; + // Normalize pathname - remove trailing slash except for root "/" + if (u.pathname !== "/" && u.pathname.endsWith("/")) { + u.pathname = u.pathname.slice(0, -1); + } + // Normalize query params: sort by key + if (u.search) { + const params = Array.from(u.searchParams.entries()); + params.sort(([a], [b]) => a.localeCompare(b)); + u.search = params.length ? "?" + params.map(([k, v]) => `${k}=${v}`).join("&") : ""; + } else { + // Ensure no empty search string + u.search = ""; + } + return u.toString(); + } catch (e) { + return input; + } +} + +// register extensions +if (!URL.prototype.normalize) + URL.prototype.normalize = function () { + return normalizeUrl(this.toString()); + }; diff --git a/src/util/util/extensions/index.ts b/src/util/util/extensions/index.ts new file mode 100644 index 00000000..46c26f4c --- /dev/null +++ b/src/util/util/extensions/index.ts @@ -0,0 +1,2 @@ +export * from "./Array"; +export * from "./Url"; \ No newline at end of file diff --git a/src/util/util/index.ts b/src/util/util/index.ts index 096db326..05bdcdf8 100644 --- a/src/util/util/index.ts +++ b/src/util/util/index.ts @@ -17,7 +17,7 @@ */ export * from "./ApiError"; -export * from "./Array"; +export * from "./extensions/Array"; export * from "./BitField"; //export * from "./Categories"; export * from "./cdn"; @@ -44,8 +44,8 @@ export * from "./String"; export * from "./Token"; export * from "./TraverseDirectory"; export * from "./WebAuthn"; -export * from "./Url"; export * from "./Gifs"; export * from "./Application"; export * from "./NameValidation"; export * from "./HelperTypes"; +export * from "./extensions"; diff --git a/tsconfig.json b/tsconfig.json index 5d408b24..f5cfbe04 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -55,8 +55,8 @@ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ /* Emit */ - "declaration": false /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, - "declarationMap": false /* Create sourcemaps for d.ts files. */, + "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, + "declarationMap": true /* Create sourcemaps for d.ts files. */, // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ "sourceMap": true /* Create source map files for emitted JavaScript files. */, // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */