mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
Leave CLI as broken
This commit is contained in:
parent
b69f20ccf4
commit
f4fd16179c
24
README.md
24
README.md
|
|
@ -4,14 +4,11 @@
|
|||
|
||||
       [](code_of_conduct.md)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This project is **not abandoned**, my laptop merely broke and I am waiting for a new one to arrive
|
||||
|
||||
## What is this?
|
||||
|
||||
This is a project to create a federated social network based on the [Lysand](https://lysand.org) protocol. It is currently in alpha phase, with basic federation and API support.
|
||||
This is a project to create a federated social network based on the [Lysand](https://lysand.org) protocol. It is currently in alpha phase, with basic federation and almost complete Mastodon API support.
|
||||
|
||||
This project aims to be a fully featured social network, with a focus on privacy, security, and performance. It will implement the Mastodon API for support with clients that already support Mastodon or Pleroma.
|
||||
This project aims to be a fully featured social network, with a focus on privacy, security, and performance. It implements the Mastodon API for support with clients that already support Mastodon or Pleroma.
|
||||
|
||||
> [!NOTE]
|
||||
> This project is not affiliated with Mastodon or Pleroma, and is not a fork of either project. It is a new project built from the ground up.
|
||||
|
|
@ -35,7 +32,7 @@ This project aims to be a fully featured social network, with a focus on privacy
|
|||
## Benchmarks
|
||||
|
||||
> [!NOTE]
|
||||
> These benchmarks are not representative of real-world performance, and are only meant to be used as a rough guide.
|
||||
> These benchmarks are not representative of real-world performance, and are only meant to be used as a rough guide. Load, and therefore performance, will vary depending on the server's hardware and software configuration, as well as user activity.
|
||||
|
||||
### Timeline Benchmarks
|
||||
|
||||
|
|
@ -67,18 +64,21 @@ $ bun run benchmarks/timelines.ts 10000
|
|||
✓ 10000 requests fulfilled in 12.44852s
|
||||
```
|
||||
|
||||
Lysand is extremely fast and can handle tens of thousands of HTTP requests per second on a good server.
|
||||
Lysand is extremely fast and can handle thousands of HTTP requests per second on a good server.
|
||||
|
||||
## How do I run it?
|
||||
|
||||
### Requirements
|
||||
|
||||
- The [Bun Runtime](https://bun.sh), version 1.0.5 or later (usage of the latest version is recommended)
|
||||
- The [Bun Runtime](https://bun.sh), version 1.0.30 or later (usage of the latest version is recommended)
|
||||
- A PostgreSQL database
|
||||
- (Optional but recommended) A Linux-based operating system
|
||||
- (Optional if you want search) A working Meiliseach instance
|
||||
|
||||
> **Note**: We will not be offerring support to Windows or MacOS users. If you are using one of these operating systems, please use a virtual machine or container to run Lysand.
|
||||
> [!WARNING]
|
||||
> Lysand has not been tested on Windows or MacOS. It is recommended to use a Linux-based operating system to run Lysand.
|
||||
>
|
||||
> We will not be offerring support to Windows or MacOS users. If you are using one of these operating systems, please use a virtual machine or container to run Lysand.
|
||||
|
||||
### Installation
|
||||
|
||||
|
|
@ -152,6 +152,9 @@ bun start
|
|||
|
||||
### Using the CLI
|
||||
|
||||
> [!WARNING]
|
||||
> The CLI is currently broken due to unknown bugs that are actively being investigated. The following instructions are for when this is fixed.
|
||||
|
||||
Lysand includes a built-in CLI for managing the server. To use it, simply run the following command:
|
||||
|
||||
```bash
|
||||
|
|
@ -279,10 +282,12 @@ Working endpoints are:
|
|||
- `/api/v1/blocks`
|
||||
- `/api/v1/mutes`
|
||||
- `/api/v2/media`
|
||||
- `/api/v1/notifications`
|
||||
|
||||
Tests needed but completed:
|
||||
|
||||
- `/api/v1/media/:id`
|
||||
- `/api/v2/media`
|
||||
- `/api/v1/favourites`
|
||||
- `/api/v1/accounts/:id/followers`
|
||||
- `/api/v1/accounts/:id/following`
|
||||
|
|
@ -335,7 +340,6 @@ Endpoints left:
|
|||
- `/api/v1/lists/:id` (`GET`, `PUT`, `DELETE`)
|
||||
- `/api/v1/markers` (`GET`, `POST`)
|
||||
- `/api/v1/lists/:id/accounts` (`GET`, `POST`, `DELETE`)
|
||||
- `/api/v1/notifications`
|
||||
- `/api/v1/notifications/:id`
|
||||
- `/api/v1/notifications/clear`
|
||||
- `/api/v1/notifications/:id/dismiss`
|
||||
|
|
|
|||
127
cli.ts
127
cli.ts
|
|
@ -1,23 +1,139 @@
|
|||
import type { Prisma } from "@prisma/client";
|
||||
import chalk from "chalk";
|
||||
import { client } from "~database/datasource";
|
||||
import { createNewLocalUser } from "~database/entities/User";
|
||||
import Table from "cli-table";
|
||||
import { rebuildSearchIndexes, MeiliIndexType } from "@meilisearch";
|
||||
import { getConfig } from "~classes/configmanager";
|
||||
import { uploadFile } from "~classes/media";
|
||||
import { getUrl } from "~database/entities/Attachment";
|
||||
import { mkdir, exists } from "fs/promises";
|
||||
import extract from "extract-zip";
|
||||
import { client } from "~database/datasource";
|
||||
import { CliBuilder, CliCommand } from "cli-parser";
|
||||
import { CliParameterType } from "~packages/cli-parser/cli-builder.type";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { ConfigManager } from "~packages/config-manager";
|
||||
|
||||
const args = process.argv;
|
||||
|
||||
const config = await new ConfigManager({}).getConfig();
|
||||
|
||||
console.error("CLI is temporarily broken, please use the Prisma CLI instead");
|
||||
process.exit(1);
|
||||
|
||||
const cliBuilder = new CliBuilder([
|
||||
new CliCommand(
|
||||
["help"],
|
||||
[],
|
||||
() => {
|
||||
cliBuilder.displayHelp();
|
||||
},
|
||||
"Shows help for the CLI"
|
||||
),
|
||||
new CliCommand<{
|
||||
username: string;
|
||||
password: string;
|
||||
email: string;
|
||||
admin: boolean;
|
||||
help: boolean;
|
||||
}>(
|
||||
["user", "create"],
|
||||
[
|
||||
{
|
||||
name: "username",
|
||||
type: CliParameterType.STRING,
|
||||
description: "Username of the user",
|
||||
needsValue: true,
|
||||
positioned: false,
|
||||
},
|
||||
{
|
||||
name: "password",
|
||||
type: CliParameterType.STRING,
|
||||
description: "Password of the user",
|
||||
needsValue: true,
|
||||
positioned: false,
|
||||
},
|
||||
{
|
||||
name: "email",
|
||||
type: CliParameterType.STRING,
|
||||
description: "Email of the user",
|
||||
needsValue: true,
|
||||
positioned: false,
|
||||
},
|
||||
{
|
||||
name: "admin",
|
||||
type: CliParameterType.BOOLEAN,
|
||||
description: "Make the user an admin",
|
||||
needsValue: false,
|
||||
positioned: false,
|
||||
},
|
||||
{
|
||||
name: "help",
|
||||
shortName: "h",
|
||||
type: CliParameterType.EMPTY,
|
||||
description: "Show help message",
|
||||
needsValue: false,
|
||||
positioned: false,
|
||||
},
|
||||
],
|
||||
(instance: CliCommand, args) => {
|
||||
const { username, password, email, admin, help } = args;
|
||||
|
||||
if (help) {
|
||||
instance.displayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if username, password and email are provided
|
||||
if (!username || !password || !email) {
|
||||
console.log(
|
||||
`${chalk.red(`✗`)} Missing username, password or email`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if user already exists
|
||||
void client.user
|
||||
.findFirst({
|
||||
where: {
|
||||
OR: [{ username }, { email }],
|
||||
},
|
||||
})
|
||||
.then(user => {
|
||||
if (user) {
|
||||
console.log(`${chalk.red(`✗`)} User already exists`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Sus");
|
||||
|
||||
// Create user
|
||||
/* const newUser = await createNewLocalUser({
|
||||
email: email,
|
||||
password: password,
|
||||
username: username,
|
||||
admin: admin,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`${chalk.green(`✓`)} Created user ${chalk.blue(
|
||||
newUser.username
|
||||
)}${admin ? chalk.green(" (admin)") : ""}`
|
||||
); */
|
||||
});
|
||||
},
|
||||
"Creates a new user",
|
||||
"bun cli user create --username admin --password password123 --email email@email.com"
|
||||
),
|
||||
]);
|
||||
|
||||
cliBuilder.processArgs(args);
|
||||
|
||||
process.exit(0);
|
||||
|
||||
/**
|
||||
* Make the text have a width of 20 characters, padding with gray dots
|
||||
* Text can be a Chalk string, in which case formatting codes should not be counted in text length
|
||||
* @param text The text to align
|
||||
*/
|
||||
const alignDots = (text: string, length = 20) => {
|
||||
/* const alignDots = (text: string, length = 20) => {
|
||||
// Remove formatting codes
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const textLength = text.replace(/\u001b\[\d+m/g, "").length;
|
||||
|
|
@ -1065,3 +1181,4 @@ switch (command) {
|
|||
}
|
||||
|
||||
process.exit(0);
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,10 +1,23 @@
|
|||
export interface CliParameter {
|
||||
name: string;
|
||||
// If not positioned, the argument will need to be called with --name value instead of just value
|
||||
/* Like -v for --version */
|
||||
shortName?: string;
|
||||
/**
|
||||
* If not positioned, the argument will need to be called with --name value instead of just value
|
||||
* @default true
|
||||
*/
|
||||
positioned?: boolean;
|
||||
// Whether the argument needs a value (requires positioned to be false)
|
||||
/* Whether the argument needs a value (requires positioned to be false) */
|
||||
needsValue?: boolean;
|
||||
optional?: true;
|
||||
type: "string" | "number" | "boolean" | "array";
|
||||
type: CliParameterType;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export enum CliParameterType {
|
||||
STRING = "string",
|
||||
NUMBER = "number",
|
||||
BOOLEAN = "boolean",
|
||||
ARRAY = "array",
|
||||
EMPTY = "empty",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { CliParameter } from "./cli-builder.type";
|
||||
import { CliParameterType, type CliParameter } from "./cli-builder.type";
|
||||
import chalk from "chalk";
|
||||
|
||||
export function startsWithArray(fullArray: any[], startArray: any[]) {
|
||||
|
|
@ -193,21 +193,21 @@ export class CliBuilder {
|
|||
if (value instanceof CliCommand) {
|
||||
writeBuffer += `${" ".repeat(depth)}${chalk.blue(key)}|${chalk.underline(value.description)}\n`;
|
||||
const positionedArgs = value.argTypes.filter(
|
||||
arg => arg.positioned
|
||||
arg => arg.positioned ?? true
|
||||
);
|
||||
const unpositionedArgs = value.argTypes.filter(
|
||||
arg => !arg.positioned
|
||||
arg => !(arg.positioned ?? true)
|
||||
);
|
||||
|
||||
for (const arg of unpositionedArgs) {
|
||||
for (const arg of positionedArgs) {
|
||||
writeBuffer += `${" ".repeat(depth + 1)}${chalk.green(
|
||||
arg.name
|
||||
)}|${
|
||||
arg.description ?? "(no description)"
|
||||
} ${arg.optional ? chalk.gray("(optional)") : ""}\n`;
|
||||
}
|
||||
for (const arg of positionedArgs) {
|
||||
writeBuffer += `${" ".repeat(depth + 1)}${chalk.yellow("--" + arg.name)}|${
|
||||
for (const arg of unpositionedArgs) {
|
||||
writeBuffer += `${" ".repeat(depth + 1)}${chalk.yellow("--" + arg.name)}${arg.shortName ? ", " + chalk.yellow("-" + arg.shortName) : ""}|${
|
||||
arg.description ?? "(no description)"
|
||||
} ${arg.optional ? chalk.gray("(optional)") : ""}\n`;
|
||||
}
|
||||
|
|
@ -253,15 +253,38 @@ export class CliBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/* type CliParametersToType<T extends CliParameter[]> = {
|
||||
[K in T[number]["name"]]: T[number]["type"] extends CliParameterType.STRING
|
||||
? string
|
||||
: T[number]["type"] extends CliParameterType.NUMBER
|
||||
? number
|
||||
: T[number]["type"] extends CliParameterType.BOOLEAN
|
||||
? boolean
|
||||
: T[number]["type"] extends CliParameterType.ARRAY
|
||||
? string[]
|
||||
: T[number]["type"] extends CliParameterType.EMPTY
|
||||
? never
|
||||
: never;
|
||||
};
|
||||
|
||||
type ExecuteFunction<T extends CliParameter[]> = (
|
||||
args: CliParametersToType<T>
|
||||
) => void; */
|
||||
|
||||
type ExecuteFunction<T> = (
|
||||
instance: CliCommand,
|
||||
args: Partial<T>
|
||||
) => Promise<void> | void;
|
||||
|
||||
/**
|
||||
* A command that can be executed from the command line
|
||||
* @param categories Example: `["user", "create"]` for the command `./cli user create --name John`
|
||||
*/
|
||||
export class CliCommand {
|
||||
export class CliCommand<T = any> {
|
||||
constructor(
|
||||
public categories: string[],
|
||||
public argTypes: CliParameter[],
|
||||
private execute: (args: Record<string, any>) => void,
|
||||
private execute: ExecuteFunction<T>,
|
||||
public description?: string,
|
||||
public example?: string
|
||||
) {}
|
||||
|
|
@ -271,13 +294,17 @@ export class CliCommand {
|
|||
* formatted with Chalk and with emojis
|
||||
*/
|
||||
displayHelp() {
|
||||
const positionedArgs = this.argTypes.filter(arg => arg.positioned);
|
||||
const unpositionedArgs = this.argTypes.filter(arg => !arg.positioned);
|
||||
const positionedArgs = this.argTypes.filter(
|
||||
arg => arg.positioned ?? true
|
||||
);
|
||||
const unpositionedArgs = this.argTypes.filter(
|
||||
arg => !(arg.positioned ?? true)
|
||||
);
|
||||
const helpMessage = `
|
||||
${chalk.green("📚 Command:")} ${chalk.yellow(this.categories.join(" "))}
|
||||
${this.description ? `${chalk.cyan(this.description)}\n` : ""}
|
||||
${chalk.magenta("🔧 Arguments:")}
|
||||
${unpositionedArgs
|
||||
${positionedArgs
|
||||
.map(
|
||||
arg =>
|
||||
`${chalk.bold(arg.name)}: ${chalk.blue(arg.description ?? "(no description)")} ${
|
||||
|
|
@ -285,10 +312,10 @@ ${unpositionedArgs
|
|||
}`
|
||||
)
|
||||
.join("\n")}
|
||||
${positionedArgs
|
||||
${unpositionedArgs
|
||||
.map(
|
||||
arg =>
|
||||
`--${chalk.bold(arg.name)}: ${chalk.blue(arg.description ?? "(no description)")} ${
|
||||
`--${chalk.bold(arg.name)}${arg.shortName ? `, -${arg.shortName}` : ""}: ${chalk.blue(arg.description ?? "(no description)")} ${
|
||||
arg.optional ? chalk.gray("(optional)") : ""
|
||||
}`
|
||||
)
|
||||
|
|
@ -328,6 +355,20 @@ ${positionedArgs
|
|||
i++;
|
||||
currentParameter = null;
|
||||
}
|
||||
} else if (arg.startsWith("-")) {
|
||||
const shortName = arg.substring(1);
|
||||
const argType = this.argTypes.find(
|
||||
argType => argType.shortName === shortName
|
||||
);
|
||||
if (argType && !argType.needsValue) {
|
||||
parsedArgs[argType.name] = true;
|
||||
} else if (argType && argType.needsValue) {
|
||||
parsedArgs[argType.name] = this.castArgValue(
|
||||
argsWithoutCategories[i + 1],
|
||||
argType.type
|
||||
);
|
||||
i++;
|
||||
}
|
||||
} else if (currentParameter) {
|
||||
parsedArgs[currentParameter.name] = this.castArgValue(
|
||||
arg,
|
||||
|
|
@ -352,13 +393,13 @@ ${positionedArgs
|
|||
|
||||
private castArgValue(value: string, type: CliParameter["type"]): any {
|
||||
switch (type) {
|
||||
case "string":
|
||||
case CliParameterType.STRING:
|
||||
return value;
|
||||
case "number":
|
||||
case CliParameterType.NUMBER:
|
||||
return Number(value);
|
||||
case "boolean":
|
||||
case CliParameterType.BOOLEAN:
|
||||
return value === "true";
|
||||
case "array":
|
||||
case CliParameterType.ARRAY:
|
||||
return value.split(",");
|
||||
default:
|
||||
return value;
|
||||
|
|
@ -370,6 +411,6 @@ ${positionedArgs
|
|||
*/
|
||||
run(argsWithoutCategories: string[]) {
|
||||
const args = this.parseArgs(argsWithoutCategories);
|
||||
this.execute(args);
|
||||
void this.execute(this, args as any);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { CliCommand, CliBuilder, startsWithArray } from "..";
|
||||
import { describe, beforeEach, it, expect, jest, spyOn } from "bun:test";
|
||||
import stripAnsi from "strip-ansi";
|
||||
import { CliParameterType } from "../cli-builder.type";
|
||||
|
||||
describe("startsWithArray", () => {
|
||||
it("should return true when fullArray starts with startArray", () => {
|
||||
|
|
@ -36,10 +37,27 @@ describe("CliCommand", () => {
|
|||
cliCommand = new CliCommand(
|
||||
["category1", "category2"],
|
||||
[
|
||||
{ name: "arg1", type: "string", needsValue: true },
|
||||
{ name: "arg2", type: "number", needsValue: true },
|
||||
{ name: "arg3", type: "boolean", needsValue: false },
|
||||
{ name: "arg4", type: "array", needsValue: true },
|
||||
{
|
||||
name: "arg1",
|
||||
type: CliParameterType.STRING,
|
||||
needsValue: true,
|
||||
},
|
||||
{
|
||||
name: "arg2",
|
||||
shortName: "a",
|
||||
type: CliParameterType.NUMBER,
|
||||
needsValue: true,
|
||||
},
|
||||
{
|
||||
name: "arg3",
|
||||
type: CliParameterType.BOOLEAN,
|
||||
needsValue: false,
|
||||
},
|
||||
{
|
||||
name: "arg4",
|
||||
type: CliParameterType.ARRAY,
|
||||
needsValue: true,
|
||||
},
|
||||
],
|
||||
() => {
|
||||
// Do nothing
|
||||
|
|
@ -65,13 +83,34 @@ describe("CliCommand", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("should cast argument values correctly", () => {
|
||||
expect(cliCommand["castArgValue"]("42", "number")).toBe(42);
|
||||
expect(cliCommand["castArgValue"]("true", "boolean")).toBe(true);
|
||||
expect(cliCommand["castArgValue"]("value1,value2", "array")).toEqual([
|
||||
it("should parse short names for arguments too", () => {
|
||||
const args = cliCommand["parseArgs"]([
|
||||
"--arg1",
|
||||
"value1",
|
||||
"value2",
|
||||
"-a",
|
||||
"42",
|
||||
"--arg3",
|
||||
"--arg4",
|
||||
"value1,value2",
|
||||
]);
|
||||
expect(args).toEqual({
|
||||
arg1: "value1",
|
||||
arg2: 42,
|
||||
arg3: true,
|
||||
arg4: ["value1", "value2"],
|
||||
});
|
||||
});
|
||||
|
||||
it("should cast argument values correctly", () => {
|
||||
expect(cliCommand["castArgValue"]("42", CliParameterType.NUMBER)).toBe(
|
||||
42
|
||||
);
|
||||
expect(
|
||||
cliCommand["castArgValue"]("true", CliParameterType.BOOLEAN)
|
||||
).toBe(true);
|
||||
expect(
|
||||
cliCommand["castArgValue"]("value1,value2", CliParameterType.ARRAY)
|
||||
).toEqual(["value1", "value2"]);
|
||||
});
|
||||
|
||||
it("should run the execute function with the parsed parameters", () => {
|
||||
|
|
@ -79,10 +118,26 @@ describe("CliCommand", () => {
|
|||
cliCommand = new CliCommand(
|
||||
["category1", "category2"],
|
||||
[
|
||||
{ name: "arg1", type: "string", needsValue: true },
|
||||
{ name: "arg2", type: "number", needsValue: true },
|
||||
{ name: "arg3", type: "boolean", needsValue: false },
|
||||
{ name: "arg4", type: "array", needsValue: true },
|
||||
{
|
||||
name: "arg1",
|
||||
type: CliParameterType.STRING,
|
||||
needsValue: true,
|
||||
},
|
||||
{
|
||||
name: "arg2",
|
||||
type: CliParameterType.NUMBER,
|
||||
needsValue: true,
|
||||
},
|
||||
{
|
||||
name: "arg3",
|
||||
type: CliParameterType.BOOLEAN,
|
||||
needsValue: false,
|
||||
},
|
||||
{
|
||||
name: "arg4",
|
||||
type: CliParameterType.ARRAY,
|
||||
needsValue: true,
|
||||
},
|
||||
],
|
||||
mockExecute
|
||||
);
|
||||
|
|
@ -109,13 +164,29 @@ describe("CliCommand", () => {
|
|||
cliCommand = new CliCommand(
|
||||
["category1", "category2"],
|
||||
[
|
||||
{ name: "arg1", type: "string", needsValue: true },
|
||||
{ name: "arg2", type: "number", needsValue: true },
|
||||
{ name: "arg3", type: "boolean", needsValue: false },
|
||||
{ name: "arg4", type: "array", needsValue: true },
|
||||
{
|
||||
name: "arg1",
|
||||
type: CliParameterType.STRING,
|
||||
needsValue: true,
|
||||
},
|
||||
{
|
||||
name: "arg2",
|
||||
type: CliParameterType.NUMBER,
|
||||
needsValue: true,
|
||||
},
|
||||
{
|
||||
name: "arg3",
|
||||
type: CliParameterType.BOOLEAN,
|
||||
needsValue: false,
|
||||
},
|
||||
{
|
||||
name: "arg4",
|
||||
type: CliParameterType.ARRAY,
|
||||
needsValue: true,
|
||||
},
|
||||
{
|
||||
name: "arg5",
|
||||
type: "string",
|
||||
type: CliParameterType.STRING,
|
||||
needsValue: true,
|
||||
positioned: true,
|
||||
},
|
||||
|
|
@ -153,31 +224,31 @@ describe("CliCommand", () => {
|
|||
[
|
||||
{
|
||||
name: "arg1",
|
||||
type: "string",
|
||||
type: CliParameterType.STRING,
|
||||
needsValue: true,
|
||||
description: "Argument 1",
|
||||
optional: true,
|
||||
},
|
||||
{
|
||||
name: "arg2",
|
||||
type: "number",
|
||||
type: CliParameterType.NUMBER,
|
||||
needsValue: true,
|
||||
description: "Argument 2",
|
||||
},
|
||||
{
|
||||
name: "arg3",
|
||||
type: "boolean",
|
||||
type: CliParameterType.BOOLEAN,
|
||||
needsValue: false,
|
||||
description: "Argument 3",
|
||||
optional: true,
|
||||
positioned: true,
|
||||
positioned: false,
|
||||
},
|
||||
{
|
||||
name: "arg4",
|
||||
type: "array",
|
||||
type: CliParameterType.ARRAY,
|
||||
needsValue: true,
|
||||
description: "Argument 4",
|
||||
positioned: true,
|
||||
positioned: false,
|
||||
},
|
||||
],
|
||||
() => {
|
||||
|
|
@ -260,7 +331,7 @@ describe("CliBuilder", () => {
|
|||
[
|
||||
{
|
||||
name: "arg1",
|
||||
type: "string",
|
||||
type: CliParameterType.STRING,
|
||||
needsValue: true,
|
||||
positioned: false,
|
||||
},
|
||||
|
|
@ -352,20 +423,28 @@ describe("CliBuilder", () => {
|
|||
[
|
||||
{
|
||||
name: "name",
|
||||
type: "string",
|
||||
type: CliParameterType.STRING,
|
||||
needsValue: true,
|
||||
description: "Name of new item",
|
||||
},
|
||||
{
|
||||
name: "delete-previous",
|
||||
type: "number",
|
||||
type: CliParameterType.NUMBER,
|
||||
needsValue: false,
|
||||
positioned: true,
|
||||
positioned: false,
|
||||
optional: true,
|
||||
description: "Also delete the previous item",
|
||||
},
|
||||
{ name: "arg3", type: "boolean", needsValue: false },
|
||||
{ name: "arg4", type: "array", needsValue: true },
|
||||
{
|
||||
name: "arg3",
|
||||
type: CliParameterType.BOOLEAN,
|
||||
needsValue: false,
|
||||
},
|
||||
{
|
||||
name: "arg4",
|
||||
type: CliParameterType.ARRAY,
|
||||
needsValue: true,
|
||||
},
|
||||
],
|
||||
() => {
|
||||
// Do nothing
|
||||
|
|
|
|||
39
server.ts
39
server.ts
|
|
@ -75,7 +75,11 @@ export const createServer = (
|
|||
return errorResponse("Route not found", 500);
|
||||
}
|
||||
|
||||
if (matchedRoute && file != undefined) {
|
||||
if (
|
||||
matchedRoute &&
|
||||
matchedRoute.name !== "/[...404]" &&
|
||||
file != undefined
|
||||
) {
|
||||
const meta = file.meta;
|
||||
|
||||
// Check for allowed requests
|
||||
|
|
@ -133,35 +137,50 @@ export const createServer = (
|
|||
configManager,
|
||||
parsedRequest,
|
||||
});
|
||||
} else {
|
||||
} else if (matchedRoute?.name === "/[...404]") {
|
||||
// Proxy response from Vite at localhost:5173 if in development mode
|
||||
if (isProd) {
|
||||
if (new URL(req.url).pathname.startsWith("/assets")) {
|
||||
// Serve from pages/dist/assets
|
||||
return new Response(
|
||||
Bun.file(`./pages/dist${new URL(req.url).pathname}`)
|
||||
const file = Bun.file(
|
||||
`./pages/dist${new URL(req.url).pathname}`
|
||||
);
|
||||
|
||||
// Serve from pages/dist/assets
|
||||
if (await file.exists()) {
|
||||
return new Response(file);
|
||||
} else return errorResponse("Asset not found", 404);
|
||||
}
|
||||
if (new URL(req.url).pathname.startsWith("/api")) {
|
||||
return errorResponse("Route not found", 404);
|
||||
}
|
||||
|
||||
const file = Bun.file(`./pages/dist/index.html`);
|
||||
|
||||
// Serve from pages/dist
|
||||
return new Response(Bun.file(`./pages/dist/index.html`));
|
||||
return new Response(file);
|
||||
} else {
|
||||
const proxy = await fetch(
|
||||
req.url.replace(
|
||||
config.http.base_url,
|
||||
"http://localhost:5173"
|
||||
)
|
||||
).catch(async e => {
|
||||
await logger.logError(
|
||||
LogLevel.ERROR,
|
||||
"Server.Proxy",
|
||||
e as Error
|
||||
);
|
||||
return errorResponse("Route not found", 404);
|
||||
});
|
||||
|
||||
if (proxy.status !== 404) {
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(undefined, {
|
||||
status: 404,
|
||||
statusText: "Route not found",
|
||||
});
|
||||
return errorResponse("Route not found", 404);
|
||||
} else {
|
||||
return errorResponse("Route not found", 404);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue