Move more extensions to extensions

This commit is contained in:
Rory&
2026-06-12 16:27:38 +02:00
parent 7fa9567a56
commit 96bb1ed05c
42 changed files with 137 additions and 90 deletions
+1 -2
View File
@@ -18,7 +18,7 @@
process.env.LOG_ROUTES = "false";
const { Stopwatch } = require("../dist/util/util/Stopwatch");
const { Stopwatch } = require("../dist/extensions/Stopwatch");
const totalSw = Stopwatch.startNew();
require("module-alias/register");
@@ -26,7 +26,6 @@ const getRouteDescriptions = require("./util/getRouteDescriptions");
const path = require("path");
const fs = require("fs");
const { NO_AUTHORIZATION_ROUTES } = require("../dist/api/middlewares/Authentication");
require("../dist/extensions");
const { bgRedBright, bgYellow, black, bgYellowBright, blue, white } = require("picocolors");
const openapiPath = path.join(__dirname, "..", "assets", "openapi.json");
+1 -1
View File
@@ -19,7 +19,7 @@
/*
Regenerates the `spacebarchat/server/assets/schemas.json` file, used for API/Gateway input validation.
*/
const { Stopwatch } = require("../dist/util/util/Stopwatch");
const { Stopwatch } = require("../dist/extensions/Stopwatch");
const totalSw = Stopwatch.startNew();
const conWarn = console.warn;
+2 -1
View File
@@ -19,8 +19,9 @@
import { Request, Response, Router } from "express";
import { route } from "@spacebar/api";
import { Application } from "@spacebar/database";
import { Config, createAppBotUser, trimSpecial } from "@spacebar/util";
import { Config, createAppBotUser } from "@spacebar/util";
import { ApplicationCreateSchema } from "@spacebar/schemas";
import { trimSpecial } from "@spacebar/extensions";
const router: Router = Router({ mergeParams: true });
+2 -1
View File
@@ -22,9 +22,10 @@ import { HTTPError } from "lambert-server/HTTPError";
import { MoreThan } from "typeorm";
import { route, verifyCaptcha } from "@spacebar/api";
import { Invite, User, ValidRegistrationToken } from "@spacebar/database";
import { Config, FieldErrors, generateToken, IpDataClient, AbuseIpDbClient, TimeSpan, Stopwatch } from "@spacebar/util";
import { Config, FieldErrors, generateToken, IpDataClient, AbuseIpDbClient } from "@spacebar/util";
import { RegisterSchema } from "@spacebar/schemas";
import { BcryptWorkerPool } from "../../../util/util/workers/bcrypt/BcryptWorkerPool";
import { Stopwatch, TimeSpan } from "@spacebar/extensions";
const router: Router = Router({ mergeParams: true });
@@ -21,8 +21,9 @@ import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server/HTTPError";
import { route } from "@spacebar/api";
import { Application, Channel, User, Webhook } from "@spacebar/database";
import { Config, DiscordApiErrors, handleFile, trimSpecial, ValidateName } from "@spacebar/util";
import { Config, DiscordApiErrors, handleFile, ValidateName } from "@spacebar/util";
import { isTextChannel, WebhookCreateSchema, WebhookType } from "@spacebar/schemas";
import { trimSpecial } from "@spacebar/extensions";
const router: Router = Router({ mergeParams: true });
+2 -1
View File
@@ -18,8 +18,9 @@
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server/HTTPError";
import { generateCode, route } from "@spacebar/api";
import { route } from "@spacebar/api";
import { Guild, Template } from "@spacebar/database";
import { generateCode } from "@spacebar/extensions";
const router: Router = Router({ mergeParams: true });
+4 -3
View File
@@ -16,12 +16,13 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Request, Response, Router } from "express";
import { Not } from "typeorm";
import { route } from "@spacebar/api";
import { Channel, Emoji, Guild, InstanceBan, Member, Recipient, Sticker, User, UserSettingsProtos } from "@spacebar/database";
import { ChannelDeleteEvent, ChannelRecipientRemoveEvent, emitEvent, Stopwatch, UserDeleteEvent } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { ChannelDeleteEvent, ChannelRecipientRemoveEvent, emitEvent, UserDeleteEvent } from "@spacebar/util";
import { ChannelType, InstanceUserDeleteSchema, PrivateUserProjection } from "@spacebar/schemas";
import { Not } from "typeorm";
import { Stopwatch } from "@spacebar/extensions";
const router = Router({ mergeParams: true });
+2 -1
View File
@@ -20,7 +20,8 @@ import { Request, Response, Router } from "express";
import { In, LessThan, FindOptionsWhere } from "typeorm";
import { route } from "@spacebar/api";
import { Message, Member, Channel, Attachment } from "@spacebar/database";
import { Snowflake, Permissions, NewUrlUserSignatureData, Stopwatch } from "@spacebar/util";
import { Snowflake, Permissions, NewUrlUserSignatureData } from "@spacebar/util";
import { Stopwatch } from "@spacebar/extensions";
const router: Router = Router({ mergeParams: true });
+2 -2
View File
@@ -16,9 +16,9 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Session } from "@spacebar/database";
import { TimeSpan } from "@spacebar/util";
import { setInterval } from "node:timers";
import { Session } from "@spacebar/database";
import { TimeSpan } from "@spacebar/extensions";
export async function initInstance() {
// TODO: clean up database and delete tombstone data
+1 -2
View File
@@ -20,7 +20,7 @@ import { HTTPError } from "lambert-server/HTTPError";
import { Equal, In, Or } from "typeorm";
import { fillMessageUrlEmbeds, randomString } from "@spacebar/api";
import { getDatabase, Application, Attachment, Channel, CloudAttachment, Guild, Member, Message, ReadState, Role, Session, Sticker, User, Webhook } from "@spacebar/database";
import { mathLogBase, arrayDistributeSequentially } from "@spacebar/extensions";
import { mathLogBase, arrayDistributeSequentially, Stopwatch } from "@spacebar/extensions";
import {
Config,
DiscordApiErrors,
@@ -36,7 +36,6 @@ import {
Permissions,
ROLE_MENTION,
Snowflake,
Stopwatch,
TraceNode,
TraceRoot,
TraceSubTree,
-1
View File
@@ -22,7 +22,6 @@ export * from "./handlers/Message";
export * from "./utility/passwordStrength";
export * from "./utility/RandomInviteID";
export * from "./handlers/route";
export * from "./utility/String";
export * from "./handlers/Voice";
export * from "./utility/captcha";
export * from "./utility/EmbedHandlers";
+2 -2
View File
@@ -22,8 +22,8 @@ import { yellow } from "picocolors";
import probe from "probe-image-size";
import { FindOptionsWhere, In } from "typeorm";
import { EmbedCache, Message } from "@spacebar/database";
import { sleep, arrayDistinctBy, arrayGroupBy } from "@spacebar/extensions";
import { Config, emitEvent, MessageUpdateEvent, normalizeUrl, OrmUtils } from "@spacebar/util";
import { sleep, arrayDistinctBy, arrayGroupBy, normalizeUrl } from "@spacebar/extensions";
import { Config, emitEvent, MessageUpdateEvent, OrmUtils } from "@spacebar/util";
import { Embed, EmbedImage, EmbedType } from "@spacebar/schemas";
export function getDefaultFetchOptions(): RequestInit {
-38
View File
@@ -1,38 +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 <https://www.gnu.org/licenses/>.
*/
import { Request } from "express";
import { ntob } from "./Base64";
import { FieldErrors, Random } from "@spacebar/util";
export function checkLength(str: string, min: number, max: number, key: string, req: Request) {
if (str.length < min || str.length > max) {
throw FieldErrors({
[key]: {
code: "BASE_TYPE_BAD_LENGTH",
message: req.t("common:field.BASE_TYPE_BAD_LENGTH", {
length: `${min} - ${max}`,
}),
},
});
}
}
export function generateCode() {
return ntob(Date.now() + Random.nextInt(0, 10000));
}
+2 -1
View File
@@ -29,7 +29,8 @@ import cluster, { Worker } from "node:cluster";
import os from "node:os";
import "reflect-metadata";
import { red, bold, yellow, cyan, blueBright, redBright } from "picocolors";
import { centerString, getRevInfoOrFail, Logo } from "@spacebar/util";
import { centerString } from "@spacebar/extensions";
import { getRevInfoOrFail, Logo } from "@spacebar/util";
import { initStats } from "./stats";
const cores = process.env.THREADS ? parseInt(process.env.THREADS) : 1;
+2 -1
View File
@@ -20,7 +20,7 @@ import { HTTPError } from "lambert-server/HTTPError";
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
import { DmChannelDTO } from "../../util/dtos";
import { ChannelCreateEvent, ChannelRecipientRemoveEvent, ThreadCreateEvent, ThreadMembersUpdateEvent } from "../../util/interfaces";
import { InvisibleCharacters, Snowflake, emitEvent, getPermission, trimSpecial, Permissions, Config, DiscordApiErrors } from "../../util/util";
import { InvisibleCharacters, Snowflake, emitEvent, getPermission, Permissions, Config, DiscordApiErrors } from "../../util/util";
import { BaseClass } from "./BaseClass";
import { Guild } from "./Guild";
import { Invite } from "./Invite";
@@ -35,6 +35,7 @@ import { Member } from "./Member";
import { ChannelPermissionOverwrite, ChannelType, PublicChannel, PublicUserProjection, ThreadMetadata } from "@spacebar/schemas";
import { OrmUtils } from "../../util/imports";
import { ThreadMember } from "./ThreadMember";
import { trimSpecial } from "@spacebar/extensions";
@Entity({
name: "channels",
+2 -1
View File
@@ -21,13 +21,14 @@ import { BeforeInsert, BeforeUpdate, Column, Entity, Index, JoinColumn, JoinTabl
import { Ban, Channel, PublicGuildRelations } from "./index";
import { ReadyGuildDTO } from "../../util/dtos";
import { GuildCreateEvent, GuildDeleteEvent, GuildMemberAddEvent, GuildMemberRemoveEvent, GuildMemberUpdateEvent, MessageCreateEvent } from "../../util/interfaces";
import { Config, emitEvent, DiscordApiErrors, Stopwatch } from "../../util/util";
import { Config, emitEvent, DiscordApiErrors } from "../../util/util";
import { BaseClassWithoutId } from "./BaseClass";
import { Guild } from "./Guild";
import { Message } from "./Message";
import { Role } from "./Role";
import { User } from "./User";
import { AvatarDecorationData, Collectibles, DisplayNameStyle, PublicMember, PublicMemberProjection, UserGuildSettings } from "@spacebar/schemas";
import { Stopwatch } from "@spacebar/extensions";
export const MemberPrivateProjection: (keyof Member)[] = [
"id",
+4 -3
View File
@@ -17,12 +17,13 @@
*/
import crypto from "node:crypto";
import { Column, CreateDateColumn, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn, RelationId } from "typeorm";
import { randomUpperString } from "@spacebar/api";
import { DateBuilder, TimeSpan } from "@spacebar/extensions";
import { User } from "./User";
import { BaseClassWithoutId } from "./BaseClass";
import { Column, CreateDateColumn, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn, RelationId } from "typeorm";
import { Activity, ClientStatus, GatewaySession, GatewaySessionClientInfo, PrivateStatus } from "../../util/interfaces";
import { randomUpperString } from "@spacebar/api";
import { DateBuilder, IpDataClient, TimeSpan } from "../../util/util";
import { IpDataClient } from "../../util/util";
@Entity({
name: "sessions",
+2 -2
View File
@@ -18,8 +18,8 @@
import { Request } from "express";
import { Column, Entity, JoinColumn, OneToMany, OneToOne } from "typeorm";
import { Config, Email, FieldErrors, Snowflake, Stopwatch, trimSpecial } from "@spacebar/util";
import { Random } from "@spacebar/util/util/Random";
import { Config, Email, FieldErrors, Snowflake } from "@spacebar/util";
import { Stopwatch, trimSpecial, Random } from "@spacebar/extensions";
import { BaseClass } from "./BaseClass";
import { Channel } from "./Channel";
import { ConnectedAccount } from "./ConnectedAccount";
@@ -1,3 +1,21 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2026 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 <https://www.gnu.org/licenses/>.
*/
// Inspired by dotnet: https://learn.microsoft.com/en-us/dotnet/api/system.random?view=net-9.0#methods
export class Random {
public static nextInt(min?: number, max?: number): number {
@@ -16,7 +16,11 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { SPECIAL_CHAR } from "./Regex";
import { Request } from "express";
import { SPECIAL_CHAR } from "@spacebar/util/util/Regex";
import { Random } from "@spacebar/extensions/Random";
import { ntob } from "@spacebar/api";
import { FieldErrors } from "@spacebar/util";
export function trimSpecial(str?: string): string {
if (!str) return "";
@@ -44,3 +48,21 @@ export function stringGlobToRegexp(str: string, flags?: string): RegExp {
const escaped = str.replace(".", "\\.").replace("?", ".").replace("*", ".*");
return new RegExp(escaped, flags);
}
export function stringCheckLength(str: string, min: number, max: number, key: string, req: Request) {
if (str.length < min || str.length > max) {
throw FieldErrors({
[key]: {
code: "BASE_TYPE_BAD_LENGTH",
// TODO: remove dependency on request (add generic field?)
message: req.t("common:field.BASE_TYPE_BAD_LENGTH", {
length: `${min} - ${max}`,
}),
},
});
}
}
export function generateCode() {
return ntob(Date.now() + Random.nextInt(0, 10000));
}
+7
View File
@@ -17,7 +17,14 @@
*/
export * from "./Array";
export * from "./DateBuilder";
export * from "./ElapsedTime";
export * from "./Math";
export * from "./Random";
export * from "./Stopwatch";
export * from "./String";
export * from "./Timespan";
export * from "./Url";
// TODO: move to a separate file
export async function sleep(ms: number) {
+2 -1
View File
@@ -18,9 +18,10 @@
import { In } from "typeorm";
import { Member, Session } from "@spacebar/database";
import { Stopwatch, timePromise } from "@spacebar/extensions";
import { WebSocket, Payload, OPCODES, Send, handleOffloadedGatewayRequest } from "@spacebar/gateway";
import { PublicMember } from "@spacebar/schemas";
import { Presence, timePromise, Stopwatch, Config, getMostRelevantSession } from "@spacebar/util";
import { Presence, Config, getMostRelevantSession } from "@spacebar/util";
// TODO: only show roles/members that have access to this channel
// TODO: config: to list all members (even those who are offline) sorted by role, or just those who are online
+1 -5
View File
@@ -19,7 +19,7 @@
import { In, Not } from "typeorm";
import { PreloadedUserSettings } from "discord-protos";
import { Capabilities, CLOSECODES, OPCODES, Payload, Send, setupListener, WebSocket } from "@spacebar/gateway";
import { arrayGroupBy } from "@spacebar/extensions";
import { arrayGroupBy, ElapsedTime, Stopwatch, timeFunction, timePromise } from "@spacebar/extensions";
import {
getDatabase,
Application,
@@ -43,7 +43,6 @@ import {
checkToken,
Config,
CurrentTokenFormatVersion,
ElapsedTime,
emitEvent,
EVENTEnum,
generateToken,
@@ -55,9 +54,6 @@ import {
ReadyGuildDTO,
ReadyUserGuildSettingsEntries,
SessionsReplace,
Stopwatch,
timeFunction,
timePromise,
TraceNode,
TraceRoot,
} from "@spacebar/util";
+2 -1
View File
@@ -18,9 +18,10 @@
import { FindManyOptions, ILike, In, MoreThan } from "typeorm";
import { getDatabase, Member, Session } from "@spacebar/database";
import { DateBuilder } from "@spacebar/extensions";
import { WebSocket, Payload, OPCODES, Send, handleOffloadedGatewayRequest } from "@spacebar/gateway";
import { RequestGuildMembersSchema } from "@spacebar/schemas";
import { Config, DateBuilder, getPermission, GuildMembersChunkEvent, Presence } from "@spacebar/util";
import { Config, getPermission, GuildMembersChunkEvent, Presence } from "@spacebar/util";
import { check } from "./instanceOf";
export async function onRequestGuildMembers(this: WebSocket, { d }: Payload) {
+2 -1
View File
@@ -17,7 +17,8 @@
*/
import { Session, VoiceState } from "@spacebar/database";
import { Event, TimeSpan } from "@spacebar/util";
import { TimeSpan } from "@spacebar/extensions";
import { Event } from "@spacebar/util";
import { WebSocket } from "./WebSocket";
import { OPCODES } from "./Constants";
import { Send } from "./Send";
+1 -1
View File
@@ -25,7 +25,7 @@ import { existsSync } from "node:fs";
// TODO: dont use deprecated APIs lol
import { FindOptionsRelationByString, FindOptionsSelectByString } from "typeorm";
import { randomUpperString } from "@spacebar/api";
import { TimeSpan } from "./Timespan";
import { TimeSpan } from "../../extensions/Timespan";
import { HTTPError } from "lambert-server/HTTPError";
import path from "node:path";
-7
View File
@@ -22,9 +22,7 @@ export * from "./BitField";
export * from "./cdn";
export * from "./Config";
export * from "./Constants";
export * from "./DateBuilder";
export * from "./email";
export * from "./ElapsedTime";
export * from "./ipc/Event";
export * from "./FieldError";
export * from "./Intents";
@@ -39,9 +37,6 @@ export * from "./ipc/RabbitMQ";
export * from "./Regex";
export * from "./Rights";
export * from "./Snowflake";
export * from "./Stopwatch";
export * from "./String";
export * from "./Timespan";
export * from "./Token";
export * from "./TraverseDirectory";
export * from "./WebAuthn";
@@ -49,7 +44,5 @@ export * from "./ChannelFlags";
export * from "./Gifs";
export * from "./Application";
export * from "./NameValidation";
export * from "./Random";
export * from "./Url";
export * from "./Version";
export * from "./Presence";
+5 -4
View File
@@ -20,11 +20,12 @@ import net, { Socket } from "node:net";
import fs, { FSWatcher } from "node:fs";
import path from "node:path";
import { red } from "picocolors";
import { BaseEventWriter } from "./BaseEventWriter";
import { Event, Stopwatch } from "@spacebar/util";
import { ProcessLifecycle } from "../../ProcessLifecycle";
import { Monitoring } from "../../../monitoring/Monitoring";
import { Gauge } from "prom-client";
import { Stopwatch } from "@spacebar/extensions";
import { Event } from "@spacebar/util";
import { Monitoring } from "../../../monitoring/Monitoring";
import { ProcessLifecycle } from "../../ProcessLifecycle";
import { BaseEventWriter } from "./BaseEventWriter";
export class UnixSocketWriter extends BaseEventWriter {
private static openConnectionsMetric: Gauge;
+1 -1
View File
@@ -2,7 +2,7 @@ import { JsonSerializer } from "./JsonSerializer";
import { describe, it } from "node:test";
import { strict as assert } from "node:assert";
import fs from "node:fs/promises";
import { Stopwatch } from "../Stopwatch";
import { Stopwatch } from "../../../extensions/Stopwatch";
import { JsonValue } from "@protobuf-ts/runtime";
describe("JsonSerializer", () => {
@@ -1,4 +1,23 @@
import { Config, DateBuilder } from "@spacebar/util";
/*
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 <https://www.gnu.org/licenses/>.
*/
import { DateBuilder } from "@spacebar/extensions";
import { Config } from "@spacebar/util";
import { AbuseIpDbBlacklistResponse, AbuseIpDbCheckResponse } from "./AbuseIpDbSampleResponses";
export class AbuseIpDbClient {
@@ -1,4 +1,23 @@
import { Config, DateBuilder } from "@spacebar/util";
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2026 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 <https://www.gnu.org/licenses/>.
*/
import { DateBuilder } from "@spacebar/extensions";
import { Config } from "@spacebar/util";
import { IpDataIpLookupResponse } from "./IpDataSampleResponses";
export class IpDataClient {
@@ -16,7 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { DateBuilder } from "@spacebar/util";
import { DateBuilder } from "@spacebar/extensions";
// https://www.stopforumspam.com/usage
export class StopForumSpamClient {
@@ -1,6 +1,6 @@
import { isMainThread, parentPort, Worker } from "node:worker_threads";
import { ProcessLifecycle } from "../../ProcessLifecycle";
import { Stopwatch } from "../../Stopwatch";
import { Stopwatch } from "../../../../extensions/Stopwatch";
import bcrypt from "bcrypt";
export class BcryptWorkerPool {