mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 05:49:16 +01:00
Finish full rewrite of server and testing systems
This commit is contained in:
parent
0e4d6b401c
commit
0541776d3d
32 changed files with 1168 additions and 916 deletions
|
|
@ -14,7 +14,7 @@ export const convertTextToHtml = async (
|
|||
content_type?: string
|
||||
) => {
|
||||
if (content_type === "text/markdown") {
|
||||
return linkifyHtml(await sanitizeHtml(parse(text)));
|
||||
return linkifyHtml(await sanitizeHtml(await parse(text)));
|
||||
} else if (content_type === "text/x.misskeymarkdown") {
|
||||
// Parse as MFM
|
||||
// TODO: Implement MFM
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
import { getConfig } from "~classes/configmanager";
|
||||
import chalk from "chalk";
|
||||
import { client } from "~database/datasource";
|
||||
import { Meilisearch } from "meilisearch";
|
||||
import type { Status, User } from "@prisma/client";
|
||||
import { ConfigManager } from "config-manager";
|
||||
import { LogLevel, type LogManager, type MultiLogManager } from "log-manager";
|
||||
|
||||
const config = getConfig();
|
||||
const config = await new ConfigManager({}).getConfig();
|
||||
|
||||
export const meilisearch = new Meilisearch({
|
||||
host: `${config.meilisearch.host}:${config.meilisearch.port}`,
|
||||
apiKey: config.meilisearch.api_key,
|
||||
});
|
||||
|
||||
export const connectMeili = async () => {
|
||||
export const connectMeili = async (logger: MultiLogManager | LogManager) => {
|
||||
if (!config.meilisearch.enabled) return;
|
||||
|
||||
if (await meilisearch.isHealthy()) {
|
||||
|
|
@ -31,14 +32,16 @@ export const connectMeili = async () => {
|
|||
.index(MeiliIndexType.Statuses)
|
||||
.updateSearchableAttributes(["content"]);
|
||||
|
||||
console.log(
|
||||
`${chalk.green(`✓`)} ${chalk.bold(`Connected to Meilisearch`)}`
|
||||
await logger.log(
|
||||
LogLevel.INFO,
|
||||
"Meilisearch",
|
||||
"Connected to Meilisearch"
|
||||
);
|
||||
} else {
|
||||
console.error(
|
||||
`${chalk.red(`✗`)} ${chalk.bold(
|
||||
`Error while connecting to Meilisearch`
|
||||
)}`
|
||||
await logger.log(
|
||||
LogLevel.CRITICAL,
|
||||
"Meilisearch",
|
||||
"Error while connecting to Meilisearch"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
|
|||
31
utils/module.ts
Normal file
31
utils/module.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { fileURLToPath } from "url";
|
||||
|
||||
/**
|
||||
* Determines whether a module is the entry point for the running node process.
|
||||
* This works for both CommonJS and ES6 environments.
|
||||
*
|
||||
* ### CommonJS
|
||||
* ```js
|
||||
* if (moduleIsEntry(module)) {
|
||||
* console.log('WOO HOO!!!');
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ### ES6
|
||||
* ```js
|
||||
* if (moduleIsEntry(import.meta.url)) {
|
||||
* console.log('WOO HOO!!!');
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const moduleIsEntry = (moduleOrImportMetaUrl: NodeModule | string) => {
|
||||
if (typeof moduleOrImportMetaUrl === "string") {
|
||||
return process.argv[1] === fileURLToPath(moduleOrImportMetaUrl);
|
||||
}
|
||||
|
||||
if (typeof require !== "undefined" && "exports" in moduleOrImportMetaUrl) {
|
||||
return require.main === moduleOrImportMetaUrl;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import { getConfig } from "~classes/configmanager";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import chalk from "chalk";
|
||||
import { ConfigManager } from "config-manager";
|
||||
import Redis from "ioredis";
|
||||
import { createPrismaRedisCache } from "prisma-redis-middleware";
|
||||
|
||||
const config = getConfig();
|
||||
const config = await new ConfigManager({}).getConfig();
|
||||
|
||||
const cacheRedis = config.redis.cache.enabled
|
||||
? new Redis({
|
||||
|
|
@ -12,7 +12,7 @@ const cacheRedis = config.redis.cache.enabled
|
|||
port: Number(config.redis.cache.port),
|
||||
password: config.redis.cache.password,
|
||||
db: Number(config.redis.cache.database ?? 0),
|
||||
})
|
||||
})
|
||||
: null;
|
||||
|
||||
cacheRedis?.on("error", e => {
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
/**
|
||||
* Takes a request, and turns FormData or query parameters
|
||||
* into a JSON object as would be returned by req.json()
|
||||
* This is a translation layer that allows clients to use
|
||||
* either FormData, query parameters, or JSON in the request
|
||||
* @param request The request to parse
|
||||
*/
|
||||
/* export async function parseRequest<T>(request: Request): Promise<Partial<T>> {
|
||||
const query = new URL(request.url).searchParams;
|
||||
let output: Partial<T> = {};
|
||||
|
||||
// Parse SearchParams arrays into JSON arrays
|
||||
const arrayKeys = [...query.keys()].filter(key => key.endsWith("[]"));
|
||||
const nonArrayKeys = [...query.keys()].filter(key => !key.endsWith("[]"));
|
||||
|
||||
for (const key of arrayKeys) {
|
||||
const value = query.getAll(key);
|
||||
query.delete(key);
|
||||
query.append(key, JSON.stringify(value));
|
||||
}
|
||||
|
||||
// Append non array keys to output
|
||||
for (const key of nonArrayKeys) {
|
||||
// @ts-expect-error Complains about type
|
||||
output[key] = query.get(key);
|
||||
}
|
||||
|
||||
const queryEntries = [...query.entries()];
|
||||
|
||||
if (queryEntries.length > 0) {
|
||||
const data: Record<string, string | string[]> = {};
|
||||
|
||||
const arrayKeys = [...query.keys()].filter(key => key.endsWith("[]"));
|
||||
|
||||
for (const key of arrayKeys) {
|
||||
const value = query.getAll(key);
|
||||
query.delete(key);
|
||||
// @ts-expect-error JSON arrays are valid
|
||||
data[key] = JSON.parse(value);
|
||||
}
|
||||
|
||||
output = {
|
||||
...output,
|
||||
...(data as T),
|
||||
};
|
||||
}
|
||||
|
||||
// if request contains a JSON body
|
||||
if (request.headers.get("Content-Type")?.includes("application/json")) {
|
||||
try {
|
||||
output = {
|
||||
...output,
|
||||
...((await request.json()) as T),
|
||||
};
|
||||
} catch {
|
||||
// Invalid JSON
|
||||
}
|
||||
}
|
||||
|
||||
// If request contains FormData
|
||||
if (request.headers.get("Content-Type")?.includes("multipart/form-data")) {
|
||||
// @ts-expect-error It hates entries() for some reason
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
const formData = [...(await request.formData()).entries()];
|
||||
|
||||
if (formData.length > 0) {
|
||||
const data: Record<string, string | File> = {};
|
||||
|
||||
for (const [key, value] of formData) {
|
||||
// If object, parse as JSON
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-base-to-string, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
data[key] = JSON.parse(value.toString());
|
||||
} catch {
|
||||
// If a file, set as a file
|
||||
if (value instanceof File) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
data[key] = value;
|
||||
} else {
|
||||
// Otherwise, set as a string
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
data[key] = value.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output = {
|
||||
...output,
|
||||
...(data as T),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
*/
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { getConfig } from "~classes/configmanager";
|
||||
import { ConfigManager } from "config-manager";
|
||||
import { sanitize } from "isomorphic-dompurify";
|
||||
|
||||
export const sanitizeHtml = async (html: string) => {
|
||||
const config = getConfig();
|
||||
const config = await new ConfigManager({}).getConfig();
|
||||
|
||||
const sanitizedHtml = sanitize(html, {
|
||||
ALLOWED_TAGS: [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue