Feat: server-infoエンドポイント / Fix: logger.tsを追跡対象に / Feat: lynqchat-jsを利用可能に / Fix: lynqchat-jsに不足していたエンドポイントを追加
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"private": true,
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
import { appendFileSync } from "node:fs";
|
||||
import { EOL } from "node:os";
|
||||
|
||||
const createLog = (
|
||||
nativeLogger: (...args: any[]) => void,
|
||||
type: string,
|
||||
...args: any[]
|
||||
) => {
|
||||
if (args[0] instanceof Array) {
|
||||
args = args[0];
|
||||
}
|
||||
|
||||
const content = `${new Date().toLocaleString()} [${type}] ${args.join("\n").replaceAll("\n", "\n ")}`;
|
||||
|
||||
nativeLogger(content);
|
||||
|
||||
try {
|
||||
appendFileSync(
|
||||
`${import.meta.dirname}/../../../../.log/system.log`,
|
||||
`${content.toString().replace(/\x1B\[[0-9;]*m/g, '')}${EOL}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(`${new Date().toLocaleString()} Logger: Failed to write to file.`);
|
||||
}
|
||||
}
|
||||
|
||||
const logger = {
|
||||
log: (...args: any[]) => createLog(console.log, "LOG", args),
|
||||
info: (...args: any[]) => createLog(console.info, "INFO", args),
|
||||
error: (...args: any[]) => createLog(console.error, "ERROR", args),
|
||||
warn: (...args: any[]) => createLog(console.warn, "WARN", args),
|
||||
}
|
||||
|
||||
export default logger;
|
||||
@@ -2,6 +2,7 @@ import type { FastifyInstance } from "fastify";
|
||||
import Setup from "./setup";
|
||||
import Primary from "./primary";
|
||||
import Me from "./me";
|
||||
import ServerInfo from "./server-info";
|
||||
|
||||
export default async function Routes(fastify: FastifyInstance) {
|
||||
await fastify.register(Setup, {
|
||||
@@ -12,6 +13,10 @@ export default async function Routes(fastify: FastifyInstance) {
|
||||
prefix: "/primary",
|
||||
});
|
||||
|
||||
await fastify.register(ServerInfo, {
|
||||
prefix: "/server-info",
|
||||
});
|
||||
|
||||
await fastify.register(Me, {
|
||||
prefix: "/me",
|
||||
});
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { DatabaseError } from "@/errors";
|
||||
import logger from "@/lib/logger";
|
||||
import { ConfigEntity } from "@/modules/entities/Config";
|
||||
import { UserEntity } from "@/modules/entities/User";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
|
||||
export default async function ServerInfo(fastify: FastifyInstance) {
|
||||
fastify.post("/", async (req, res) => {
|
||||
try {
|
||||
const config = fastify.orm.em.getRepository(ConfigEntity);
|
||||
const user = fastify.orm.em.getRepository(UserEntity);
|
||||
const configCount = await config.count();
|
||||
const userCount = await user.count();
|
||||
|
||||
return res.send({
|
||||
isInitialized: configCount > 0,
|
||||
isFirstAdminExists: userCount > 0,
|
||||
userCount,
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error("Database error:", err);
|
||||
|
||||
return res.code(500).send(DatabaseError());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { ConfigEntity } from "@/modules/entities/Config";
|
||||
import { UserEntity } from "@/modules/entities/User";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
|
||||
export default async function ServerInfo(fastify: FastifyInstance) {
|
||||
fastify.post("/", async (req, res) => {
|
||||
const config = fastify.orm.em.getRepository(ConfigEntity);
|
||||
const user = fastify.orm.em.getRepository(UserEntity);
|
||||
const configCount = await config.count();
|
||||
const userCount = await user.count();
|
||||
|
||||
return res.send({
|
||||
isInitialized: configCount > 0,
|
||||
isFirstAdminExists: userCount > 0,
|
||||
userCount,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -11,15 +11,16 @@
|
||||
"dependencies": {
|
||||
"dexie": "^4.3.0",
|
||||
"vue": "^3.5.24",
|
||||
"vue-router": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.10.1",
|
||||
"vue-router": "^5.0.2",
|
||||
"lynqchat-js": "workspace:*",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"typescript": "~5.9.3",
|
||||
"vite": "^8.0.0",
|
||||
"vue-tsc": "^3.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.10.1"
|
||||
},
|
||||
"packageManager": "pnpm@10.29.1"
|
||||
}
|
||||
|
||||
@@ -24,4 +24,10 @@
|
||||
import { RouterView } from "vue-router";
|
||||
import routerStatus from "@/lib/router";
|
||||
import Progress from "@/components/Progress.vue";
|
||||
import LynqChat from "lynqchat-js";
|
||||
import type ApiMap from "lynqchat-js/1.0.0-alpha.0/map"
|
||||
|
||||
const client = new LynqChat<ApiMap>({
|
||||
origin: window.origin,
|
||||
});
|
||||
</script>
|
||||
@@ -1,10 +1,37 @@
|
||||
{
|
||||
"name": "lynqchat",
|
||||
"name": "lynqchat-js",
|
||||
"description": "A LynqChat official JavaScript SDK.",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {},
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"license": "AGPL-3.0-only",
|
||||
"author": {
|
||||
"name": "Last2014",
|
||||
"email": "info@last2014.com",
|
||||
"url": "https://about.last2014.com"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc && tsc-alias && copyfiles -u 1 \"src/**/*.d.ts\" dist",
|
||||
"prepare": "tsc && tsc-alias && copyfiles -u 1 \"src/**/*.d.ts\" dist"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"./*": {
|
||||
"import": "./dist/*.js",
|
||||
"types": "./dist/*.d.ts"
|
||||
},
|
||||
"./*/*": {
|
||||
"import": "./dist/*/*.js",
|
||||
"types": "./dist/*/*.d.ts"
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@10.29.1",
|
||||
"dependencies": {
|
||||
"copyfiles": "^2.4.1",
|
||||
"tsc-alias": "^1.8.16",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import SetupCreateAdmin from "./setup/create-admin";
|
||||
import SetupInitilization from "./setup/initialization";
|
||||
|
||||
type ApiMap =
|
||||
SetupInitilization &
|
||||
SetupCreateAdmin;
|
||||
|
||||
export default ApiMap;
|
||||
@@ -0,0 +1,12 @@
|
||||
import { InputError, InputNoneError } from "../../modules/error/input";
|
||||
import ErrorBase from "../../modules/error";
|
||||
import DatabaseError from "../../modules/error/database";
|
||||
import Success from "../../modules/response/success";
|
||||
import YetInitializationError from "../../modules/error/yet_init";
|
||||
|
||||
export default interface Me {
|
||||
"me": {
|
||||
body: never;
|
||||
response: Success | DatabaseError | InputError | InputNoneError | YetInitializationError;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { InputError, InputNoneError } from "../../modules/error/input";
|
||||
import ErrorBase from "../../modules/error";
|
||||
import DatabaseError from "../../modules/error/database";
|
||||
import Success from "../../modules/response/success";
|
||||
import YetInitializationError from "../../modules/error/yet_init";
|
||||
import { UserSchema } from "./signup";
|
||||
|
||||
export default interface PrimarySignin {
|
||||
"primary/signin": {
|
||||
body: Pick<UserSchema, "userid" | "password">;
|
||||
response: (Success & {
|
||||
token: string;
|
||||
}) | DatabaseError | ErrorBase<{
|
||||
bad: "client",
|
||||
code: "auth_input_wrong",
|
||||
message: "ユーザー名かパスワードが違います。",
|
||||
}> | InputError | InputNoneError | YetInitializationError;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { InputError, InputNoneError } from "../../modules/error/input";
|
||||
import ErrorBase from "../../modules/error";
|
||||
import DatabaseError from "../../modules/error/database";
|
||||
import Success from "../../modules/response/success";
|
||||
import YetInitializationError from "../../modules/error/yet_init";
|
||||
|
||||
export interface UserSchema {
|
||||
userid: string;
|
||||
username: string;
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export default interface PrimarySignup {
|
||||
"primary/signup": {
|
||||
body: UserSchema;
|
||||
response: Success | DatabaseError | InputError | InputNoneError | YetInitializationError;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { InputError, InputNoneError } from "../../modules/error/input";
|
||||
import ErrorBase from "../../modules/error";
|
||||
import DatabaseError from "../../modules/error/database";
|
||||
|
||||
export default interface ServerInfo {
|
||||
"server-info": {
|
||||
body: {
|
||||
name: string;
|
||||
description: string;
|
||||
requiredInvitationCode: boolean;
|
||||
force?: "use_force_initialization";
|
||||
};
|
||||
response: Success | DatabaseError;
|
||||
};
|
||||
}
|
||||
@@ -1,23 +1,17 @@
|
||||
import { InputError, InputNoneError } from "../../modules/error/input";
|
||||
import ErrorBase from "../../modules/error";
|
||||
import DatabaseError from "../../modules/error/database";
|
||||
import Success from "../../modules/response/success";
|
||||
import YetInitializationError from "../../modules/error/yet_init";
|
||||
import { UserSchema } from "../primary/signup";
|
||||
|
||||
export default interface SetupCreateAdmin {
|
||||
"setup/create-admin": {
|
||||
body: {
|
||||
userid: string;
|
||||
username: string;
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
body: UserSchema;
|
||||
response: Success | DatabaseError | ErrorBase<{
|
||||
bad: "client",
|
||||
code: "yet_initialization",
|
||||
message: "初期設定が行われていません。",
|
||||
}> | ErrorBase<{
|
||||
bad: "client",
|
||||
code: "first_admin_already_exists",
|
||||
message: "最初の管理者ユーザーは既に存在します。",
|
||||
}> | InputError | InputNoneError;
|
||||
}> | InputError | InputNoneError | YetInitializationError;
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { InputError, InputNoneError } from "../../modules/error/input";
|
||||
import ErrorBase from "../../modules/error";
|
||||
import DatabaseError from "../../modules/error/database";
|
||||
import Success from "../../modules/response/success";
|
||||
|
||||
export default interface SetupInitilization {
|
||||
"setup/initilization": {
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import Me from "./api/me";
|
||||
import PrimarySignin from "./api/primary/signin";
|
||||
import PrimarySignup from "./api/primary/signup";
|
||||
import ServerInfo from "./api/server-info";
|
||||
import SetupCreateAdmin from "./api/setup/create-admin";
|
||||
import SetupInitilization from "./api/setup/initialization";
|
||||
|
||||
type ApiMap =
|
||||
SetupCreateAdmin &
|
||||
SetupInitilization &
|
||||
ServerInfo &
|
||||
PrimarySignin &
|
||||
PrimarySignup &
|
||||
Me;
|
||||
|
||||
export default ApiMap;
|
||||
@@ -5,9 +5,9 @@ type ErrorType<R = unknown> = {
|
||||
reason?: R,
|
||||
}
|
||||
|
||||
type ErrorBase<E extends ErrorType<any>> = {
|
||||
type ErrorBase<E extends ErrorType<any> = ErrorType> = {
|
||||
success: false;
|
||||
error: E;
|
||||
}
|
||||
};
|
||||
|
||||
export default ErrorBase;
|
||||
@@ -1,3 +1,5 @@
|
||||
import ErrorBase from ".";
|
||||
|
||||
export type InputError = ErrorBase<{
|
||||
bad: "client";
|
||||
code: "input_wrong";
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
type YetInitializationError = ErrorBase<{
|
||||
bad: "client";
|
||||
code: "yet_initialization";
|
||||
message: "初期設定が行われていません。";
|
||||
}>;
|
||||
|
||||
export default YetInitializationError;
|
||||
@@ -14,7 +14,7 @@ type BodyArgs<M, E extends keyof M> =
|
||||
[];
|
||||
|
||||
export default class LynqChat<
|
||||
M extends { [K in keyof M]: { body?: any; response: any } }
|
||||
M extends { [K in keyof M]: { body: any; response: any } }
|
||||
> {
|
||||
readonly origin: string;
|
||||
readonly retry: number;
|
||||
@@ -44,25 +44,20 @@ export default class LynqChat<
|
||||
public async request<E extends keyof M>(
|
||||
endpoint: E,
|
||||
...args: BodyArgs<M, E>
|
||||
): Promise<M[E]["response"]>;
|
||||
public async request(
|
||||
endpoint: string,
|
||||
body?: any
|
||||
): Promise<any>;
|
||||
public async request(
|
||||
endpoint: string,
|
||||
...args: any[]
|
||||
): Promise<any> {
|
||||
): Promise<M[E]["response"]> {
|
||||
const body = args[0] !== undefined
|
||||
? JSON.stringify(args[0])
|
||||
: undefined;
|
||||
|
||||
const req = await lynqFetch(
|
||||
this.origin,
|
||||
this.retry,
|
||||
this.waiting,
|
||||
endpoint,
|
||||
endpoint as string,
|
||||
{
|
||||
method: "POST",
|
||||
cache: "no-store",
|
||||
body: args[0],
|
||||
body,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -7,16 +7,11 @@
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"declarationDir": "./dist/types",
|
||||
"declarationDir": "./dist",
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"baseUrl": "./src/",
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
],
|
||||
},
|
||||
"tsc-alias": {
|
||||
"resolveFullPaths": true,
|
||||
|
||||
Reference in New Issue
Block a user