feat(chat): added base for chat service

added front html

nigel in the mud

route function with openapi - gen

clean up the code a little

after pull request
This commit is contained in:
NigeParis 2025-11-11 10:02:05 +01:00 committed by Maix0
parent 73a4946d17
commit 9ce9fa44e4
122 changed files with 9354 additions and 2615 deletions

View file

@ -11,20 +11,20 @@
"dependencies": {
"@fastify/cookie": "^11.0.2",
"@fastify/jwt": "^9.1.0",
"@fastify/swagger": "^9.6.0",
"@fastify/swagger": "^9.6.1",
"@fastify/swagger-ui": "^5.2.3",
"@types/bcrypt": "^6.0.0",
"bcrypt": "^6.0.0",
"better-sqlite3": "^11.10.0",
"fastify": "^5.6.1",
"fastify": "^5.6.2",
"fastify-plugin": "^5.1.0",
"joi": "^18.0.1",
"otp": "^1.1.2",
"typebox": "^1.0.51",
"typebox": "^1.0.53",
"uuidv7": "^1.0.2"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.13",
"@types/node": "^22.19.0"
"@types/node": "^22.19.1"
}
}

View file

@ -118,7 +118,7 @@ export const authPlugin = fp<{ onlySchema?: boolean }>(async (fastify, { onlySch
.clearCookie('token', { path: '/' })
.makeResponse(401, 'notLoggedIn', 'auth.noUser');
}
req.authUser = { id: user.id, name: tok.who };
req.authUser = { id: user.id, name: user.display_name };
}
catch {
return res

View file

@ -1,6 +1,6 @@
<!DOCTYPE HTML>
<html>
<!--
<head>
<title>Demo Page For Login :)</title>
</head>
@ -34,6 +34,6 @@
</div>
<pre id="d-response"></pre>
<script src="./login_demo.js"> </script>
</body>
</body> -->
</html>

View file

@ -1,115 +1,4 @@
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
};
const tUsername = document.querySelector('#t-username');
const iUsername = document.querySelector('#i-username');
const iPassword = document.querySelector('#i-password');
const iOtp = document.querySelector('#i-otp');
const bOtpSend = document.querySelector('#b-otpSend');
const bLogin = document.querySelector('#b-login');
const bLoginGuest = document.querySelector('#b-login-guest');
const bLogout = document.querySelector('#b-logout');
const bSignin = document.querySelector('#b-signin');
const bWhoami = document.querySelector('#b-whoami');
const bOtpStatus = document.querySelector('#b-otpStatus');
const bOtpEnable = document.querySelector('#b-otpEnable');
const bOtpDisable = document.querySelector('#b-otpDisable');
const dResponse = document.querySelector('#d-response');
function setResponse(obj) {
const obj_str = JSON.stringify(obj, null, 4);
dResponse.innerText = obj_str;
}
let otpToken = null;
bLoginGuest.addEventListener('click', async () => {
const res = await fetch('/api/auth/guest', { method: 'POST' });
const json = await res.json();
setResponse(json);
if (json.kind === 'success') {
if (json?.payload?.token) {document.cookie = `token=${json?.payload?.token}`;}
}
});
bOtpSend.addEventListener('click', async () => {
const res = await fetch('/api/auth/otp', { method: 'POST', body: JSON.stringify({ code: iOtp.value, token: otpToken }), headers });
const json = await res.json();
setResponse(json);
if (json.kind === 'success') {
if (json?.payload?.token) {document.cookie = `token=${json?.payload?.token}`;}
}
});
bOtpStatus.addEventListener('click', async () => {
const res = await fetch('/api/auth/statusOtp');
const json = await res.json();
setResponse(json);
});
bOtpEnable.addEventListener('click', async () => {
const res = await fetch('/api/auth/enableOtp', { method: 'PUT' });
const json = await res.json();
setResponse(json);
});
bOtpDisable.addEventListener('click', async () => {
const res = await fetch('/api/auth/disableOtp', { method: 'PUT' });
const json = await res.json();
setResponse(json);
});
bWhoami.addEventListener('click', async () => {
let username = '';
try {
const res = await fetch('/api/user/info/me');
const json = await res.json();
setResponse(json);
if (json?.kind === 'success') {username = json?.payload?.name;}
else {username = `<not logged in:${json.msg}>`;}
}
catch {
username = '<not logged in: threw>';
}
tUsername.innerText = username;
});
bLogin.addEventListener('click', async () => {
const name = iUsername.value;
const password = iPassword.value;
const res = await fetch('/api/auth/login', { method: 'POST', body: JSON.stringify({ name, password }), headers });
const json = await res.json();
if (json?.kind === 'otpRequired') {
otpToken = json?.payload?.token;
}
else if (json?.kind === 'success') {
if (json?.payload?.token) {document.cookie = `token=${json?.payload?.token}`;}
}
setResponse(json);
});
bLogout.addEventListener('click', async () => {
const res = await fetch('/api/auth/logout', { method: 'POST' });
setResponse(await res.json());
});
bSignin.addEventListener('click', async () => {
const name = iUsername.value;
const password = iPassword.value;
const res = await fetch('/api/auth/signin', { method: 'POST', body: JSON.stringify({ name, password }), headers });
const json = await res.json();
if (json?.payload?.token) {document.cookie = `token=${json?.payload?.token};`;}
setResponse(json);
});
// const headers = {
// 'Accept': 'application/json',
// 'Content-Type': 'application/json',
// };

View file

@ -1,7 +1,7 @@
{
"openapi": "3.1.0",
"info": {
"version": "9.6.0",
"version": "9.6.1",
"title": "@fastify/swagger"
},
"components": {
@ -144,26 +144,50 @@
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
"anyOf": [
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"failure"
]
},
"msg": {
"enum": [
"enableOtp.failure.noUser",
"enableOtp.failure.noSecret"
]
}
}
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
}
}
]
}
}
}
@ -782,26 +806,52 @@
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
"anyOf": [
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
}
}
]
}
}
}

View file

@ -23,14 +23,14 @@
"@fastify/multipart": "^9.3.0",
"@fastify/sensible": "^6.0.3",
"@fastify/static": "^8.3.0",
"typebox": "^1.0.51",
"confbox": "^0.2.2",
"fastify": "^5.6.1",
"fastify": "^5.6.2",
"fastify-cli": "^7.4.1",
"fastify-plugin": "^5.1.0"
"fastify-plugin": "^5.1.0",
"typebox": "^1.0.53"
},
"devDependencies": {
"@types/node": "^22.19.0",
"@types/node": "^22.19.1",
"rollup-plugin-node-externals": "^8.1.2",
"vite": "^7.2.2",
"vite-tsconfig-paths": "^5.1.4"

View file

@ -27,6 +27,7 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
void req;
void res;
try {
console.log('DEBUG ----- guest login backend');
const adjective = getRandomFromList(fastify.words.adjectives);
const noun = getRandomFromList(fastify.words.nouns);

2
src/chat/.dockerignore Normal file
View file

@ -0,0 +1,2 @@
/dist
/node_modules

8
src/chat/README.md Normal file
View file

@ -0,0 +1,8 @@
# Nginx Configuration
You want to have a new microservice ?
Edit/add a file in `conf/locations/`
take example on `conf/locations/icons.conf` on how to make a reverse proxy and on how to serve static files
# Good Luck Have Fun

18
src/chat/entrypoint.sh Normal file
View file

@ -0,0 +1,18 @@
#!/bin/sh
set -e
set -x
# do anything here
mkdir -p /volumes/static/chat/
cp -r /extra/chat.html /volumes/static/chat/chat.html
cp -r /extra/chat.js /volumes/static/chat/chat.js
cp -r /extra/style.css /volumes/static/chat/style.css
# chmod -R a+r /volumes/static/chat || true
# run the CMD [ ... ] from the dockerfile
exec "$@"

0
src/chat/extra/.gitkeep Normal file
View file

4
src/chat/extra/chat.html Normal file
View file

@ -0,0 +1,4 @@
<!DOCTYPE HTML>
<html>
<!-- OLD HTML to be deleted later -->
</html>

1
src/chat/extra/chat.js Normal file
View file

@ -0,0 +1 @@
// OLD JS file to be deleted later

2
src/chat/extra/style.css Normal file
View file

@ -0,0 +1,2 @@
/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */
/* Old css to be deleted later */

130
src/chat/openapi.json Normal file
View file

@ -0,0 +1,130 @@
{
"openapi": "3.1.0",
"info": {
"version": "9.6.1",
"title": "@fastify/swagger"
},
"components": {
"schemas": {}
},
"paths": {
"/api/chat/test": {
"get": {
"operationId": "chatTest",
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg",
"payload"
],
"properties": {
"kind": {
"enum": [
"success"
]
},
"msg": {
"enum": [
"chat.success"
]
},
"payload": {
"type": "object",
"required": [
"name",
"id",
"guest"
],
"properties": {
"name": {
"type": "string"
},
"id": {
"type": "string"
},
"guest": {
"type": "boolean"
}
}
}
}
}
}
}
},
"401": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
},
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
}
]
}
}
}
}
}
}
}
},
"servers": [
{
"url": "https://local.maix.me:8888",
"description": "direct from docker"
},
{
"url": "https://local.maix.me:8000",
"description": "using fnginx"
}
]
}

43
src/chat/package.json Normal file
View file

@ -0,0 +1,43 @@
{
"type": "module",
"private": false,
"name": "chat",
"version": "1.0.0",
"description": "This project was bootstrapped with Fastify-CLI.",
"main": "app.ts",
"directories": {
"test": "test"
},
"scripts": {
"start": "npm run build && node dist/run.js",
"build": "vite build",
"build:prod": "vite build --outDir=/dist --minify=true --sourcemap=false",
"build:openapi": "VITE_ENTRYPOINT=src/openapi.ts vite build && node dist/openapi.cjs >openapi.json"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@fastify/autoload": "^6.3.1",
"@fastify/formbody": "^8.0.2",
"@fastify/multipart": "^9.3.0",
"@fastify/sensible": "^6.0.3",
"@fastify/static": "^8.3.0",
"@fastify/websocket": "^11.2.0",
"@sinclair/typebox": "^0.34.41",
"@tailwindcss/vite": "^4.1.17",
"esbuild": "^0.24.2",
"fastify": "^5.6.2",
"fastify-cli": "^7.4.1",
"fastify-plugin": "^5.1.0",
"jose": "^6.1.1",
"sharp": "^0.34.5",
"tailwindcss": "^4.1.17"
},
"devDependencies": {
"@types/node": "^22.19.1",
"rollup-plugin-node-externals": "^8.1.2",
"vite": "^7.2.2",
"vite-tsconfig-paths": "^5.1.4"
}
}

45
src/chat/src/app.ts Normal file
View file

@ -0,0 +1,45 @@
import { FastifyPluginAsync } from 'fastify';
import fastifyFormBody from '@fastify/formbody';
import fastifyMultipart from '@fastify/multipart';
import * as db from '@shared/database';
import * as auth from '@shared/auth';
import * as swagger from '@shared/swagger';
import * as utils from '@shared/utils';
declare const __SERVICE_NAME: string;
// @ts-expect-error: import.meta.glob is a vite thing. Typescript doesn't know this...
const plugins = import.meta.glob('./plugins/**/*.ts', { eager: true });
// @ts-expect-error: import.meta.glob is a vite thing. Typescript doesn't know this...
const routes = import.meta.glob('./routes/**/*.ts', { eager: true });
// When using .decorate you have to specify added properties for Typescript
declare module 'fastify' {
export interface FastifyInstance {
image_store: string;
}
}
const app: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
void opts;
await fastify.register(utils.useMakeResponse);
await fastify.register(swagger.useSwagger, { service: __SERVICE_NAME });
await fastify.register(db.useDatabase as FastifyPluginAsync, {});
await fastify.register(auth.jwtPlugin as FastifyPluginAsync, {});
await fastify.register(auth.authPlugin as FastifyPluginAsync, {});
// Place here your custom code!
for (const plugin of Object.values(plugins)) {
void fastify.register(plugin as FastifyPluginAsync, {});
}
for (const route of Object.values(routes)) {
void fastify.register(route as FastifyPluginAsync, {});
}
void fastify.register(fastifyFormBody, {});
void fastify.register(fastifyMultipart, {});
fastify.get('/monitoring', () => 'Ok');
};
export default app;
export { app };

21
src/chat/src/openapi.ts Normal file
View file

@ -0,0 +1,21 @@
import f, { FastifyPluginAsync } from 'fastify';
import * as swagger from '@shared/swagger';
import * as auth from '@shared/auth';
declare const __SERVICE_NAME: string;
// @ts-expect-error: import.meta.glob is a vite thing. Typescript doesn't know this...
const routes = import.meta.glob('./routes/**/*.ts', { eager: true });
async function start() {
const fastify = f({ logger: false });
await fastify.register(auth.authPlugin, { onlySchema: true });
await fastify.register(swagger.useSwagger, { service: __SERVICE_NAME });
for (const route of Object.values(routes)) {
await fastify.register(route as FastifyPluginAsync, {});
}
await fastify.ready();
console.log(JSON.stringify(fastify.swagger(), undefined, 4));
}
start();

View file

@ -0,0 +1,16 @@
# Plugins Folder
Plugins define behavior that is common to all the routes in your
application. Authentication, caching, templates, and all the other cross
cutting concerns should be handled by plugins placed in this folder.
Files in this folder are typically defined through the
[`fastify-plugin`](https://github.com/fastify/fastify-plugin) module,
making them non-encapsulated. They can define decorators and set hooks
that will then be used in the rest of your application.
Check out:
* [The hitchhiker's guide to plugins](https://fastify.dev/docs/latest/Guides/Plugins-Guide/)
* [Fastify decorators](https://fastify.dev/docs/latest/Reference/Decorators/).
* [Fastify lifecycle](https://fastify.dev/docs/latest/Reference/Lifecycle/).

View file

@ -0,0 +1,10 @@
import fp from 'fastify-plugin';
import sensible, { FastifySensibleOptions } from '@fastify/sensible';
/**
* This plugins adds some utilities to handle http errors
*
* @see https://github.com/fastify/fastify-sensible
*/
export default fp<FastifySensibleOptions>(async (fastify) => {
fastify.register(sensible);
});

View file

@ -0,0 +1,31 @@
import { FastifyPluginAsync } from 'fastify';
import { MakeStaticResponse, typeResponse } from '@shared/utils';
import { Type } from '@sinclair/typebox';
export const ChatRes = {
200: typeResponse('success', 'chat.success', {
name: Type.String(),
id: Type.String(),
guest: Type.Boolean(),
}),
};
export type ChatResType = MakeStaticResponse<typeof ChatRes>;
const route: FastifyPluginAsync = async (fastify): Promise<void> => {
fastify.get(
'/api/chat/test',
{
schema: {
response: ChatRes,
operationId: 'chatTest',
},
config: { requireAuth: true },
},
async (req, res) => {
console.log('/api/chat called =================>');
res.makeResponse(200, 'success', 'chat.success', { name: req.authUser!.name, 'id': req.authUser!.id, guest: false });
},
);
};
export default route;

36
src/chat/src/run.ts Normal file
View file

@ -0,0 +1,36 @@
// this sould only be used by the docker file !
import fastify, { FastifyInstance } from 'fastify';
import app from './app';
const start = async () => {
const envToLogger = {
development: {
transport: {
target: 'pino-pretty',
options: {
translateTime: 'HH:MM:ss Z',
ignore: 'pid,hostname',
},
},
},
production: true,
test: false,
};
const f: FastifyInstance = fastify({ logger: envToLogger.development });
try {
process.on('SIGTERM', () => {
f.log.info('Requested to shutdown');
process.exit(134);
});
console.log('-------->Serving static files from:');
await f.register(app, {});
await f.listen({ port: 80, host: '0.0.0.0' });
}
catch (err) {
f.log.error(err);
process.exit(1);
};
};
start();

15
src/chat/tsconfig.json Normal file
View file

@ -0,0 +1,15 @@
// {
// "extends": "../tsconfig.base.json",
// "compilerOptions": {
// "skipLibCheck": true, // skips type checking for all .d.ts files
// "moduleResolution": "node",
// "esModuleInterop": true,
// "types": ["node"] },
// "include": ["src/**/*.ts"]
// }
{
"extends": "../tsconfig.base.json",
"compilerOptions": {},
"include": ["src/**/*.ts"]
}

53
src/chat/vite.config.js Normal file
View file

@ -0,0 +1,53 @@
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import nodeExternals from 'rollup-plugin-node-externals';
import path from 'node:path';
import fs from 'node:fs';
function collectDeps(...pkgJsonPaths) {
const allDeps = new Set();
for (const pkgPath of pkgJsonPaths) {
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
for (const dep of Object.keys(pkg.dependencies || {})) {
allDeps.add(dep);
}
for (const peer of Object.keys(pkg.peerDependencies || {})) {
allDeps.add(peer);
}
}
return Array.from(allDeps);
};
const externals = collectDeps(
'./package.json',
'../@shared/package.json',
);
export default defineConfig({
root: __dirname,
define: {
__SERVICE_NAME: '"chat"',
},
// service root
plugins: [tsconfigPaths(), nodeExternals()],
build: {
ssr: true,
outDir: 'dist',
emptyOutDir: true,
lib: {
entry: path.resolve(__dirname, process.env.VITE_ENTRYPOINT ?? 'src/run.ts'),
// adjust main entry
formats: ['cjs'],
// CommonJS for Node.js
fileName: () => 'index.js',
},
rollupOptions: {
external: externals,
},
target: 'node22',
// or whatever Node version you use
sourcemap: true,
minify: false,
// for easier debugging
},
});

View file

@ -22,14 +22,14 @@
"@fastify/multipart": "^9.3.0",
"@fastify/sensible": "^6.0.3",
"@fastify/static": "^8.3.0",
"fastify": "^5.6.1",
"fastify": "^5.6.2",
"fastify-cli": "^7.4.1",
"fastify-plugin": "^5.1.0",
"raw-body": "^3.0.1",
"sharp": "^0.34.5"
},
"devDependencies": {
"@types/node": "^22.19.0",
"@types/node": "^22.19.1",
"rollup-plugin-node-externals": "^8.1.2",
"vite": "^7.2.2",
"vite-tsconfig-paths": "^5.1.4"

View file

@ -1,7 +1,7 @@
{
"openapi": "3.1.0",
"info": {
"version": "9.6.0",
"version": "9.6.1",
"title": "@fastify/swagger"
},
"servers": [
@ -160,26 +160,50 @@
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
"anyOf": [
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"failure"
]
},
"msg": {
"enum": [
"enableOtp.failure.noUser",
"enableOtp.failure.noSecret"
]
}
}
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
}
}
]
}
}
}
@ -816,26 +840,52 @@
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
"anyOf": [
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
}
}
]
}
}
}
@ -949,26 +999,52 @@
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
"anyOf": [
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
}
}
]
}
}
}
@ -1030,6 +1106,117 @@
"openapi_other"
]
}
},
"/api/chat/test": {
"get": {
"operationId": "chatTest",
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg",
"payload"
],
"properties": {
"kind": {
"enum": [
"success"
]
},
"msg": {
"enum": [
"chat.success"
]
},
"payload": {
"type": "object",
"required": [
"name",
"id",
"guest"
],
"properties": {
"name": {
"type": "string"
},
"id": {
"type": "string"
},
"guest": {
"type": "boolean"
}
}
}
}
}
}
}
},
"401": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
},
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
}
]
}
}
}
}
},
"tags": [
"openapi_other"
]
}
}
},
"components": {

View file

@ -7,7 +7,8 @@
"./@shared",
"./icons",
"./user",
"./auth"
"./auth",
"./chat"
],
"lint-staged": {
"*": [
@ -26,18 +27,20 @@
"devDependencies": {
"@eslint/js": "^9.39.1",
"@openapitools/openapi-generator-cli": "^2.25.0",
"@typescript-eslint/eslint-plugin": "^8.46.3",
"@typescript-eslint/parser": "^8.46.3",
"@typescript-eslint/eslint-plugin": "^8.46.4",
"@typescript-eslint/parser": "^8.46.4",
"eslint": "^9.39.1",
"husky": "^9.1.7",
"lint-staged": "^16.2.6",
"openapi-generator-cli": "^1.0.0",
"openapi-typescript": "^7.10.1",
"rimraf": "^5.0.10",
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.3"
"typescript-eslint": "^8.46.4",
"vite": "^7.2.2"
},
"dependencies": {
"@redocly/cli": "^2.11.0",
"@redocly/cli": "^2.11.1",
"bindings": "^1.5.0"
}
}

1316
src/pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,8 @@ apis:
root: ./auth/openapi.json
user:
root: ./user/openapi.json
chat:
root: ./chat/openapi.json
rules:
info-license: warn

View file

@ -1,7 +1,7 @@
{
"openapi": "3.1.0",
"info": {
"version": "9.6.0",
"version": "9.6.1",
"title": "@fastify/swagger"
},
"components": {
@ -85,26 +85,52 @@
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
"anyOf": [
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
{
"type": "object",
"required": [
"kind",
"msg"
],
"properties": {
"kind": {
"enum": [
"notLoggedIn"
]
},
"msg": {
"enum": [
"auth.noCookie",
"auth.invalidKind",
"auth.noUser",
"auth.invalid"
]
}
}
}
}
]
}
}
}

View file

@ -23,13 +23,13 @@
"@fastify/multipart": "^9.3.0",
"@fastify/sensible": "^6.0.3",
"@fastify/static": "^8.3.0",
"typebox": "^1.0.51",
"fastify": "^5.6.1",
"fastify": "^5.6.2",
"fastify-cli": "^7.4.1",
"fastify-plugin": "^5.1.0"
"fastify-plugin": "^5.1.0",
"typebox": "^1.0.53"
},
"devDependencies": {
"@types/node": "^22.19.0",
"@types/node": "^22.19.1",
"rollup-plugin-node-externals": "^8.1.2",
"vite": "^7.2.2",
"vite-tsconfig-paths": "^5.1.4"