refactor: change project strcut to monorepo

This commit is contained in:
moonrailgun 2024-01-20 16:22:44 +08:00
parent 153e2bf499
commit 601c167d36
59 changed files with 12260 additions and 1930 deletions

View File

@ -14,7 +14,7 @@ RUN pnpm build
# make sure run after pnpm build completed
# Push client(only support pure text message)
# RUN pip install apprise --break-system-packages
RUN pip install apprise --break-system-packages
# remove unused source file
RUN rm -rf ./src

View File

@ -1,7 +0,0 @@
{
"verbose": true,
"watch": ["./src/server", "./prisma"],
"ext": "ts",
"delay": 1000,
"exec": "ts-node --transpileOnly ./src/server/main.ts"
}

View File

@ -3,136 +3,35 @@
"private": true,
"version": "1.4.3",
"scripts": {
"dev": "nodemon",
"dev": "concurrently --kill-others npm:dev:server npm:dev:web",
"dev:web": "cd src/client && pnpm dev",
"dev:server": "cd src/server && pnpm dev",
"start": "cross-env NODE_ENV=production node ./dist/src/server/main.js",
"start:docker": "pnpm db:migrate:apply && pnpm db:generate && pnpm start",
"test": "vitest",
"build": "pnpm build:tracker && pnpm build:client && pnpm build:server && pnpm build:geo",
"build:client": "vite build",
"build:server": "tsc -p tsconfig.server.json",
"build": "pnpm build:tracker && pnpm build:server && pnpm build:client && pnpm build:geo",
"build:client": "cd src/client && pnpm build",
"build:server": "cd src/server && pnpm build",
"build:tracker": "ts-node scripts/build-tracker.ts",
"build:geo": "ts-node scripts/build-geo.ts",
"build:openapi": "ts-node scripts/build-openapi-schema.ts",
"postinstall": "pnpm db:generate",
"check:type": "tsc --noEmit --skipLibCheck --module esnext",
"db:generate": "prisma generate",
"db:migrate:dev": "prisma migrate dev",
"db:migrate:apply": "prisma migrate deploy",
"db:studio": "prisma studio",
"release": "release-it",
"release:patch": "release-it -i patch"
},
"dependencies": {
"@ant-design/charts": "^1.4.2",
"@ant-design/icons": "^5.2.5",
"@loadable/component": "^5.16.3",
"@monaco-editor/react": "^4.6.0",
"@paralleldrive/cuid2": "^2.2.2",
"@prisma/client": "^5.4.2",
"@tanstack/react-query": "^4.33.0",
"@trpc/client": "^10.38.4",
"@trpc/react-query": "^10.38.4",
"@trpc/server": "^10.38.4",
"@types/uuid": "^9.0.3",
"antd": "^5.9.3",
"array-move": "^3.0.1",
"axios": "^1.5.0",
"badge-maker": "^3.3.1",
"bcryptjs": "^2.4.3",
"clsx": "^2.0.0",
"colord": "^2.9.3",
"compose-middleware": "^5.0.1",
"compression": "^1.7.4",
"copy-to-clipboard": "^3.3.3",
"cors": "^2.8.5",
"croner": "^7.0.1",
"dayjs": "^1.11.9",
"detect-browser": "^5.3.0",
"dotenv": "^16.3.1",
"eventemitter-strict": "^1.0.1",
"execa": "^5.1.1",
"express": "^4.18.2",
"express-async-errors": "^3.1.1",
"express-validator": "^7.0.1",
"filesize": "^10.0.12",
"fs-extra": "^11.1.1",
"is-localhost-ip": "^2.0.0",
"isolated-vm": "^4.6.0",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"maxmind": "^4.3.11",
"millify": "^6.1.0",
"morgan": "^1.10.0",
"nanoid": "^3.3.6",
"nodemailer": "^6.9.5",
"passport": "^0.6.0",
"passport-jwt": "^4.0.1",
"ping": "^0.4.4",
"pretty-ms": "7.0.1",
"puppeteer": "^21.3.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-easy-sort": "^1.5.3",
"react-grid-layout": "1.4.2",
"react-icons": "^4.12.0",
"react-resizable": "^3.0.5",
"react-router": "^6.15.0",
"react-router-dom": "^6.15.0",
"request-ip": "^3.3.0",
"socket.io": "^4.7.2",
"socket.io-client": "^4.7.2",
"str2int": "^1.1.0",
"swagger-ui-express": "^5.0.0",
"tcp-ping": "^0.1.1",
"trpc-openapi": "^1.2.0",
"ts-node": "^10.9.1",
"uuid": "^9.0.0",
"vite-express": "^0.10.0",
"winston": "^3.11.0",
"yup": "^1.2.0",
"zod": "^3.22.2",
"zod-prisma": "^0.5.4",
"zustand": "^4.4.1"
},
"devDependencies": {
"@release-it/conventional-changelog": "^8.0.1",
"@types/bcryptjs": "^2.4.3",
"@types/compression": "^1.7.2",
"@types/cors": "^2.8.15",
"@types/express": "^4.17.17",
"@types/fs-extra": "^11.0.3",
"@types/jsonwebtoken": "^9.0.2",
"@types/loadable__component": "^5.13.8",
"@types/lodash": "^4.14.198",
"@types/lodash-es": "^4.17.9",
"@types/morgan": "^1.9.5",
"@types/node": "^18.17.12",
"@types/nodemailer": "^6.4.11",
"@types/passport": "^1.0.12",
"@types/passport-jwt": "^3.0.9",
"@types/ping": "^0.4.2",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/react-grid-layout": "^1.3.5",
"@types/react-resizable": "^3.0.7",
"@types/request-ip": "^0.0.38",
"@types/swagger-ui-express": "^4.1.5",
"@types/tar": "^6.1.5",
"@types/tcp-ping": "^0.1.5",
"@vitejs/plugin-react": "^4.0.4",
"autoprefixer": "^10.4.15",
"concurrently": "^8.2.2",
"cross-env": "^7.0.3",
"nodemon": "^2.0.22",
"postcss": "^8.4.29",
"prisma": "^5.4.2",
"prisma-json-types-generator": "^3.0.3",
"prisma-zod-generator": "^0.8.13",
"release-it": "^17.0.1",
"tailwindcss": "^3.3.3",
"tar": "^6.1.15",
"typescript": "^5.2.2",
"vite": "^4.4.9",
"vitest": "^1.1.3"
"vite": "^5.0.12"
},
"dependencies": {
"dayjs": "^1.11.9",
"eventemitter-strict": "^1.0.1",
"zod": "^3.22.2"
}
}

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,4 @@
packages:
- 'src/client'
- 'src/server'
- 'website'

View File

@ -13,7 +13,7 @@ vite
formats: ['iife'],
},
emptyOutDir: false,
outDir: resolve(__dirname, '../public'),
outDir: resolve(__dirname, '../dist/src/server/public'),
},
})
.then((res) => {

View File

@ -1,7 +1,7 @@
import { AreaConfig, Area } from '@ant-design/charts';
import { Select } from 'antd';
import dayjs, { Dayjs } from 'dayjs';
import { uniqBy } from 'lodash';
import { uniqBy } from 'lodash-es';
import React, { useState, useMemo } from 'react';
import { useSocketSubscribeList } from '../../api/socketio';
import { trpc } from '../../api/trpc';

View File

@ -8,6 +8,6 @@
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/client/main.tsx"></script>
<script type="module" src="/main.tsx"></script>
</body>
</html>

60
src/client/package.json Normal file
View File

@ -0,0 +1,60 @@
{
"name": "@tianji/client",
"private": true,
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "vite --port 10000",
"build": "vite build",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "moonrailgun <moonrailgun@gmail.com>",
"dependencies": {
"@ant-design/charts": "^1.4.2",
"@ant-design/icons": "^5.2.6",
"@loadable/component": "^5.16.3",
"@monaco-editor/react": "^4.6.0",
"@tanstack/react-query": "4.33.0",
"@trpc/client": "^10.45.0",
"@trpc/react-query": "^10.45.0",
"antd": "^5.13.1",
"array-move": "^3.0.1",
"axios": "^1.5.0",
"clsx": "^2.1.0",
"colord": "^2.9.3",
"copy-to-clipboard": "^3.3.3",
"dayjs": "^1.11.9",
"eventemitter-strict": "^1.0.1",
"filesize": "^10.0.12",
"lodash-es": "^4.17.21",
"millify": "^6.1.0",
"pretty-ms": "^9.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-easy-sort": "^1.5.3",
"react-grid-layout": "1.4.2",
"react-icons": "^4.12.0",
"react-resizable": "^3.0.5",
"react-router": "^6.15.0",
"react-router-dom": "^6.15.0",
"socket.io-client": "^4.7.2",
"str2int": "^1.1.0",
"uuid": "^9.0.1",
"zod": "^3.22.2",
"zustand": "^4.4.1"
},
"devDependencies": {
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/react-grid-layout": "^1.3.5",
"@types/react-resizable": "^3.0.7",
"@vitejs/plugin-react": "^4.0.4",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.31",
"tailwindcss": "^3.3.5",
"vite": "^5.0.12",
"vitest": "^1.2.1"
}
}

View File

@ -3,4 +3,4 @@ module.exports = {
tailwindcss: {},
autoprefixer: {},
},
}
};

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
(function(){"use strict";(h=>{const{screen:{width:K,height:O},navigator:{language:R},location:N,localStorage:S,document:i,history:m}=h,{hostname:A,pathname:U,search:_}=N,{currentScript:g}=i;if(!g)return;const l="data-",C="false",d=g.getAttribute.bind(g),q=d(l+"website-id"),P=d(l+"host-url"),z=d(l+"auto-track")!==C,I=d(l+"do-not-track"),x=d(l+"domains")||"",J=x.split(",").map(t=>t.trim()),M=`${P?P.replace(/\/$/,""):g.src.split("/").slice(0,-1).join("/")}/api/website/send`,B=`${K}x${O}`,F=/data-tianji-event-([\w-_]+)/,E=l+"tianji-event",G=300,D=(t,r,e)=>{const n=t[r];return(...a)=>(e.apply(null,a),n.apply(t,a))},H=t=>{try{return new URL(t).pathname}catch{return t}},p=()=>({website:q,hostname:A,screen:B,language:R,title:L,url:y,referrer:k}),Q=()=>{const{doNotTrack:t,navigator:r,external:e}=h,n="msTrackingProtectionEnabled",a=()=>e&&n in e&&e[n](),c=t||r.doNotTrack||r.msDoNotTrack||a();return c=="1"||c==="yes"},$=()=>S&&S.getItem("tianji.disabled")||I&&Q()||x&&!J.includes(A),j=(t,r,e)=>{e&&(k=y,y=H(e.toString()),y!==k&&setTimeout(b,G))},V=()=>{const t=e=>{const n=e.getAttribute.bind(e),a=n(E);if(a){const c={};return e.getAttributeNames().forEach(s=>{const u=s.match(F);u&&(c[u[1]]=n(s))}),b(a,c)}return Promise.resolve()},r=e=>{const n=(s,u)=>{let o=s;for(let T=0;T<u;T++){if(o.tagName==="A")return o;if(o=o.parentElement,!o)return null}return null},a=e.target,c=a.tagName==="A"?a:n(a,10);if(c){const{href:s,target:u}=c,o=u==="_blank"||e.ctrlKey||e.shiftKey||e.metaKey||e.button&&e.button===1;if(c.getAttribute(E)&&s)return o||e.preventDefault(),t(c).then(()=>{o||(N.href=s)})}else t(a)};i.addEventListener("click",r,!0)},W=()=>{const t=([n])=>{L=n&&n.target?n.target.text:void 0},r=new MutationObserver(t),e=i.querySelector("head > title");e&&r.observe(e,{subtree:!0,characterData:!0,childList:!0})},f=(t,r="event")=>{if($())return;const e={"Content-Type":"application/json"};return typeof v<"u"&&(e["x-tianji-cache"]=v),fetch(M,{method:"POST",body:JSON.stringify({type:r,payload:t}),headers:e}).then(n=>n.text()).then(n=>v=n).catch(()=>{})},b=(t,r)=>f(typeof t=="string"?{...p(),name:t,data:typeof r=="object"?r:void 0}:typeof t=="object"?t:typeof t=="function"?t(p()):p()),X=t=>f({...p(),data:t},"identify");h.tianji||(h.tianji={track:b,identify:X});let y=`${U}${_}`,k=i.referrer,L=i.title,v,w;if(z&&!$()){m.pushState=D(m,"pushState",j),m.replaceState=D(m,"replaceState",j),V(),W();const t=()=>{i.readyState==="complete"&&!w&&(b(),w=!0)};i.addEventListener("readystatechange",t,!0),t()}})(window)})();

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,6 +1,6 @@
import { create } from 'zustand';
import { Layouts, Layout } from 'react-grid-layout';
import { mapValues } from 'lodash';
import { mapValues } from 'lodash-es';
import { v1 as uuid } from 'uuid';
export type DashboardItemType =

View File

@ -3,7 +3,14 @@ import colors from 'tailwindcss/colors';
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'],
content: {
relative: true,
files: [
'./index.html',
'./components/**/*.{js,jsx,ts,tsx}',
'./pages/**/*.{js,jsx,ts,tsx}',
],
},
theme: {
extend: {
colors: {

19
src/client/vite.config.ts Normal file
View File

@ -0,0 +1,19 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/
export default defineConfig({
root: __dirname,
plugins: [react()],
build: {
outDir: '../../dist/src/server/public',
},
clearScreen: false,
server: {
proxy: {
'/trpc': {
target: 'http://localhost:12345',
},
},
},
});

1
src/server/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
public/

View File

@ -2,7 +2,6 @@ import 'dotenv/config';
import './init';
import express from 'express';
import 'express-async-errors';
import ViteExpress from 'vite-express';
import compression from 'compression';
import swaggerUI from 'swagger-ui-express';
import passport from 'passport';
@ -45,6 +44,7 @@ app.use(express.json());
app.use(passport.initialize());
app.use(morgan('tiny'));
app.use(cors());
app.use(express.static('dist'));
// http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header
app.disable('x-powered-by');
@ -77,11 +77,9 @@ app.use((err: any, req: any, res: any, next: any) => {
});
httpServer.listen(port, () => {
ViteExpress.bind(app, httpServer, () => {
logger.info(`Server is listening on port ${port}...`);
if (env.allowOpenapi) {
logger.info(`Openapi UI: http://127.0.0.1:${port}/open/_ui`);
}
logger.info(`Website: http://127.0.0.1:${port}`);
});
});

7
src/server/nodemon.json Normal file
View File

@ -0,0 +1,7 @@
{
"verbose": true,
"watch": ["./"],
"ext": "ts",
"delay": 1000,
"exec": "ts-node --transpileOnly ./main.ts"
}

88
src/server/package.json Normal file
View File

@ -0,0 +1,88 @@
{
"name": "@tianji/server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon",
"build": "tsc -p tsconfig.server.json",
"postinstall": "pnpm db:generate",
"db:generate": "prisma generate",
"db:migrate:dev": "prisma migrate dev",
"db:migrate:apply": "prisma migrate deploy",
"db:studio": "prisma studio",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "moonrailgun <moonrailgun@gmail.com>",
"dependencies": {
"@paralleldrive/cuid2": "^2.2.2",
"@prisma/client": "5.4.2",
"@trpc/server": "^10.38.4",
"axios": "^1.5.0",
"badge-maker": "^3.3.1",
"bcryptjs": "^2.4.3",
"compose-middleware": "^5.0.1",
"compression": "^1.7.4",
"cors": "^2.8.5",
"croner": "^8.0.0",
"dayjs": "^1.11.9",
"detect-browser": "^5.3.0",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-async-errors": "^3.1.1",
"express-validator": "^7.0.1",
"fs-extra": "^11.2.0",
"is-localhost-ip": "^2.0.0",
"isolated-vm": "^4.6.0",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
"maxmind": "^4.3.18",
"morgan": "^1.10.0",
"nanoid": "^5.0.4",
"nodemailer": "^6.9.8",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"ping": "^0.4.4",
"puppeteer": "^21.7.0",
"request-ip": "^3.3.0",
"socket.io": "^4.7.4",
"swagger-ui-express": "^5.0.0",
"tcp-ping": "^0.1.1",
"trpc-openapi": "^1.2.0",
"ts-node": "^10.9.1",
"uuid": "^9.0.1",
"vite-express": "^0.13.0",
"winston": "^3.11.0",
"yup": "^1.3.3",
"zod": "^3.22.2",
"zod-prisma": "^0.5.4"
},
"devDependencies": {
"@types/bcryptjs": "^2.4.3",
"@types/compression": "^1.7.2",
"@types/cors": "^2.8.15",
"@types/express": "^4.17.17",
"@types/fs-extra": "^11.0.3",
"@types/jsonwebtoken": "^9.0.5",
"@types/lodash": "^4.14.198",
"@types/morgan": "^1.9.5",
"@types/node": "^18.17.12",
"@types/nodemailer": "^6.4.11",
"@types/passport": "^1.0.12",
"@types/passport-jwt": "^3.0.9",
"@types/ping": "^0.4.2",
"@types/request-ip": "^0.0.38",
"@types/swagger-ui-express": "^4.1.5",
"@types/tcp-ping": "^0.1.5",
"@types/uuid": "^9.0.7",
"execa": "^5.1.1",
"nodemon": "^3.0.3",
"prisma": "5.4.2",
"prisma-json-types-generator": "3.0.3",
"prisma-zod-generator": "0.8.13",
"tailwindcss": "^3.3.5",
"vite": "^5.0.12",
"vitest": "^1.2.1"
}
}

View File

@ -16,6 +16,10 @@ export const WorkspaceModelSchema = z.object({
* [DashboardLayout]
*/
dashboardLayout: jsonSchema,
/**
* [CommonPayload]
*/
settings: jsonSchema,
createdAt: z.date(),
updatedAt: z.date(),
})

View File

@ -3,7 +3,6 @@ import { body, header, param, validate } from '../middleware/validate';
import { recordServerStatus } from '../model/serverStatus';
import fs from 'fs-extra';
import path from 'path';
import { env } from '../utils/env';
export const serverStatusRouter = Router();

View File

@ -26,7 +26,7 @@ import {
} from '../../model/_schema';
import { OPENAPI_TAG } from '../../utils/const';
import { OpenApiMeta } from 'trpc-openapi';
import { MonitorStatusPageModelSchema } from '../../../../prisma/zod';
import { MonitorStatusPageModelSchema } from '../../prisma/zod';
import { runCodeInVM } from '../../model/monitor/provider/custom';
export const monitorRouter = router({

View File

@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"include": ["./**/*.ts", "../shared/**/*.ts", "../types/**/*.ts"],
"exclude": ["node_modules/**/*", "dist"],
"compilerOptions": {
"rootDirs": ["./", "../"],
"outDir": "../../dist",
"noEmit": false
}
}

View File

@ -1,7 +1,7 @@
import { z } from 'zod';
import { MonitorStatusPageListSchema } from '../../prisma/zod/schemas';
import { MonitorStatusPageListSchema } from '../server/prisma/zod/schemas';
export * as schemas from '../../prisma/zod/index';
export * as schemas from '../server/prisma/zod/index';
export * from './server';
export * from './monitor';
export * from './utils';

View File

@ -1,6 +1,9 @@
import type { Monitor } from '@prisma/client';
import type { MonitorModelSchema } from '../server/prisma/zod';
import { ExactType } from './utils';
import { schemas } from '.';
import z from 'zod';
type Monitor = z.infer<typeof MonitorModelSchema>;
export type MonitorInfo = ExactType<
Monitor,

View File

@ -3,4 +3,4 @@ export type ExactType<T, U extends Partial<T>> = Omit<T, keyof U> & U;
export type PickRequired<T, U extends keyof T> = Omit<T, keyof U> &
Required<Pick<T, U>>;
export type { MaybePromise } from '@trpc/server';
export type MaybePromise<TType> = Promise<TType> | TType;

View File

@ -1,10 +0,0 @@
{
"extends": "./tsconfig.json",
"include": ["./src/server/**/*.ts", "./src/shared/**/*.ts", "./src/types/**/*.ts"],
"exclude": ["node_modules/**/*", "dist"],
"compilerOptions": {
"rootDirs": ["./", "../"],
"outDir": "./dist",
"noEmit": false
}
}

View File

@ -1,7 +0,0 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
});