Skip to content
This repository has been archived by the owner on Jul 27, 2024. It is now read-only.

Commit

Permalink
refactor: monorepo setup
Browse files Browse the repository at this point in the history
  • Loading branch information
didinele committed Feb 1, 2023
1 parent f6f3290 commit 7f9419f
Show file tree
Hide file tree
Showing 43 changed files with 2,024 additions and 1,567 deletions.
12 changes: 12 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
**/node_modules
.env
.env.*.example

coverage
**/dist/*
**/Dockerfile
docker-compose.yml

.pnp.*

.turbo
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DATABASE_PORT=5432 # You should only change this if you need 2 instances on the same machine
DATABASE_URL="postgresql://modmail:admin@localhost:${DATABASE_PORT}/modmail" # You should almost never change this, unless you know what you're doing
NODE_ENV=prod # Change to dev if you're trying to work on the project locally
DISCORD_CLIENT_ID= # Copy this from the dev portal
DISCORD_TOKEN= # Copy this from the dev portal
3 changes: 1 addition & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
"rules": {
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-extraneous-class": "off",
"import/extensions": "error",
"curly": ["error", "all"],
"eqeqeq": ["error", "always", { "null": "ignore" }],
"no-eq-null": "off",
"no-unused-vars": "off",
"import/extensions": "off",
"no-useless-constructor": "off",
"unicorn/require-post-message-target-origin": "off"
}
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ node_modules
.env

coverage/*
dist/*
**/dist/*

.yarn/*
!.yarn/patches
Expand All @@ -11,3 +11,6 @@ dist/*
!.yarn/sdks
!.yarn/versions
.pnp.*
logs

.turbo
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn build && yarn lint && yarn test
yarn build && yarn lint
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/*
coverage/*
dist/*
**/dist/*
.yarn/*
.turbo
26 changes: 26 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM node:16-alpine
LABEL name "somebot"

WORKDIR /usr/somebot

RUN apk add --update \
&& apk add --no-cache ca-certificates \
&& apk add --no-cache --virtual .build-deps curl git python3 alpine-sdk libc6-compat

COPY turbo.json package.json tsconfig.json yarn.lock .yarnrc.yml ./
COPY .yarn ./.yarn

COPY packages/api/package.json ./packages/api/package.json
COPY packages/bot/package.json ./packages/bot/package.json

RUN yarn --immutable

COPY prisma ./prisma
RUN yarn prisma generate

COPY packages/api ./packages/api
COPY packages/bot ./packages/bot

RUN yarn build

RUN yarn workspaces focus --all --production
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# template

Simple template for monolith ChatSift projects.
Simple template for ChatSift bots.

This template repository is licensed under a modified version of the MIT license, allowing you to do whatever you want with the source code and setup here without the need to provide credit/the original LICENSE file.
38 changes: 38 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
version: '3.7'

services:
postgres:
image: postgres:12-alpine
environment:
POSTGRES_USER: 'somebot'
POSTGRES_PASSWORD: 'admin'
POSTGRES_DB: 'somebot'
volumes:
- postgres-data:/var/lib/postgresql/data
restart: unless-stopped
ports:
- 127.0.0.1:${DATABASE_PORT}:5432
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U somebot']
interval: 10s
timeout: 5s

bot:
image: chatsift/somebot
build:
context: ./
dockerfile: ./Dockerfile
env_file:
- ./.env
environment:
DATABASE_URL: 'postgresql://somebot:admin@postgres:5432/somebot'
restart: unless-stopped
volumes:
- ./logs:/usr/somebot/logs
depends_on:
- postgres
command: ['node', '--enable-source-maps', '--no-warnings', './packages/bot/dist/index.js']

volumes:
postgres-data:
name: 'somebot-postgres-data'
44 changes: 23 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
{
"name": "template",
"description": "owo",
"name": "@chatsift/somebot",
"description": "This does cool stuff",
"packageManager": "[email protected]",
"main": "./dist/index.js",
"version": "0.1.0-dev",
"type": "module",
"private": true,
"version": "0.0.0",
"workspaces": [
"packages/*"
],
"repository": {
"type": "git",
"url": "https://github.com/chatsift/template.git"
"url": "https://github.com/chatsift/bot-template.git"
},
"bugs": {
"url": "https://github.com/chatsift/template/issues"
"url": "https://github.com/chatsift/bot-template/issues"
},
"homepage": "https://github.com/chatsift/template",
"homepage": "https://github.com/chatsift/bot-template",
"scripts": {
"lint": "eslint src --ext .ts && prettier --check --plugin-search-dir=. .",
"build": "tsc",
"test": "vitest run",
"lint": "turbo run lint && prettier --check --plugin-search-dir=. .",
"build": "turbo run build",
"format": "prettier --write --plugin-search-dir=. .",
"prisma": "dotenv -e .env prisma",
"deploy-commands": "rimraf ./packages/bot/dist && turbo run --no-cache build --filter ./packages/bot && dotenv -e .env -v DEPLOY=true -- node --enable-source-maps ./packages/bot/dist/index.js",
"start-bot": "dotenv -e .env -- node --enable-source-maps ./packages/bot/dist/index.js",
"start-api": "dotenv -e .env -- node --enable-source-maps ./packages/api/dist/index.js",
"prepare": "is-ci || husky install",
"update": "yarn upgrade-interactive"
},
Expand All @@ -28,22 +33,19 @@
"@commitlint/cli": "^17.4.2",
"@commitlint/config-angular": "^17.4.2",
"@types/node": "^16.18.11",
"@typescript-eslint/eslint-plugin": "^5.49.0",
"@typescript-eslint/parser": "^5.49.0",
"@vitest/coverage-c8": "^0.28.3",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"dotenv-cli": "^7.0.0",
"eslint": "^8.33.0",
"eslint-config-neon": "^0.1.40",
"eslint-plugin-typescript-sort-keys": "^2.1.0",
"husky": "^8.0.3",
"is-ci": "^3.0.1",
"prettier": "^2.8.3",
"prettier-eslint": "^15.0.1",
"typescript": "^4.9.4",
"vitest": "^0.28.3"
},
"dependencies": {
"reflect-metadata": "^0.1.13",
"tslib": "^2.5.0",
"tsyringe": "^4.7.0"
"prisma": "^4.9.0",
"rimraf": "^4.1.2",
"turbo": "~1.6.3",
"typescript": "^4.9.5"
}
}
1 change: 1 addition & 0 deletions packages/api/not_importable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
throw new Error('This module should only be used for compile-time imports. It should not be imported in runtime.');
43 changes: 43 additions & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "@chatsift/somebot-api",
"main": "./not_importable.js",
"types": "./dist/index.d.ts",
"version": "0.1.0",
"type": "module",
"files": [
"dist"
],
"scripts": {
"lint": "eslint src --ext .ts",
"build": "tsc"
},
"engines": {
"node": ">=16.9.0"
},
"devDependencies": {
"@types/cors": "^2.8.13",
"@types/node": "^16.18.11",
"@types/pino": "^7.0.5",
"prisma": "^4.9.0",
"typescript": "^4.9.5"
},
"dependencies": {
"@chatsift/pino-rotate-file": "^0.1.2",
"@chatsift/readdir": "^0.2.0",
"@chatsift/rest-utils": "^0.6.2",
"@discordjs/rest": "^1.5.0",
"@hapi/boom": "^10.0.0",
"@prisma/client": "^4.9.0",
"@sapphire/shapeshift": "^3.8.1",
"cors": "^2.8.5",
"discord-api-types": "^0.37.31",
"helmet": "^5.1.1",
"pino": "^8.8.0",
"pino-pretty": "^8.1.0",
"polka": "^1.0.0-next.22",
"prisma-error-enum": "^0.1.3",
"reflect-metadata": "^0.1.13",
"tslib": "^2.5.0",
"tsyringe": "^4.7.0"
}
}
60 changes: 60 additions & 0 deletions packages/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import 'reflect-metadata';
import { dirname, join } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { readdirRecurse } from '@chatsift/readdir';
import type { Route } from '@chatsift/rest-utils';
import { attachHttpUtils, sendBoom } from '@chatsift/rest-utils';
import { REST } from '@discordjs/rest';
import { Boom, isBoom, notFound } from '@hapi/boom';
import { PrismaClient } from '@prisma/client';
import cors from 'cors';
import helmet from 'helmet';
import type { Middleware } from 'polka';
import polka from 'polka';
import { container } from 'tsyringe';
import { Env } from './util/env.js';
import { logger } from './util/logger.js';

const env = container.resolve(Env);
container.register(PrismaClient, { useValue: new PrismaClient() });
container.register(REST, { useValue: new REST().setToken(env.discordToken) });

const app = polka({
onError(err, _, res) {
res.setHeader('content-type', 'application/json');
const boom = isBoom(err) ? err : new Boom(err);

if (boom.output.statusCode === 500) {
logger.error(boom, boom.message);
}

sendBoom(boom, res);
},
onNoMatch(_, res) {
res.setHeader('content-type', 'application/json');
sendBoom(notFound(), res);
},
}).use(
cors({
origin: env.cors,
credentials: true,
}),
helmet({ contentSecurityPolicy: env.isProd ? undefined : false }) as Middleware,
attachHttpUtils(),
);

const path = join(dirname(fileURLToPath(import.meta.url)), 'routes');
const files = readdirRecurse(path, { fileExtensions: ['js'] });

for await (const file of files) {
const mod = (await import(pathToFileURL(file).toString())) as { default?: new () => Route<any, any> };
if (mod.default) {
const route = container.resolve(mod.default);
logger.info(route.info, 'Registering route');
route.register(app);
}
}

app.listen(env.port, () => logger.info(`Listening to requests on port ${env.port}`));

export * from './routeTypes.js';
49 changes: 49 additions & 0 deletions packages/api/src/routeTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type {
InferRoutePath,
InferRouteMethod,
InferRouteBody,
InferRouteResult,
RouteMethod,
} from '@chatsift/rest-utils';
import type * as routes from './routes/index';

type Narrow<T, U> = T extends U ? T : never;
type ConstructorToType<TConstructor> = TConstructor extends new (...args: any[]) => infer T ? T : never;
type RoutesByClassNames = {
[K in keyof typeof routes]: ConstructorToType<(typeof routes)[K]>;
};
type RoutesByPaths = {
[Path in InferRoutePath<RoutesByClassNames[keyof RoutesByClassNames]>]: Narrow<
RoutesByClassNames[keyof RoutesByClassNames],
{ info: { path: Path } }
>;
};

type RouteMethodMap = {
[RouteMethod.get]: 'get';
[RouteMethod.post]: 'post';
[RouteMethod.put]: 'put';
[RouteMethod.delete]: 'delete';
[RouteMethod.patch]: 'patch';
};

export type ModmailRoutes = {
[Path in keyof RoutesByPaths]: {
[Method in RouteMethodMap[InferRouteMethod<RoutesByPaths[Path]>]]: Narrow<
RoutesByPaths[Path],
{ info: { method: Method } }
>;
};
};

export type InferModmailRouteBody<
TPath extends keyof ModmailRoutes,
TMethod extends keyof ModmailRoutes[TPath],
> = InferRouteBody<ModmailRoutes[TPath][TMethod]>;

export type InferModmailRouteResult<
TPath extends keyof ModmailRoutes,
TMethod extends keyof ModmailRoutes[TPath],
> = InferRouteResult<ModmailRoutes[TPath][TMethod]>;

export * from './util/models.js';
25 changes: 25 additions & 0 deletions packages/api/src/routes/helloWorld.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Route, RouteMethod } from '@chatsift/rest-utils';
import { PrismaClient } from '@prisma/client';
import type { Middleware, Request, Response } from 'polka';
import { singleton } from 'tsyringe';
import type { GuildSettings } from '../util/models.js';

@singleton()
export default class extends Route<GuildSettings, never> {
public info = {
method: RouteMethod.get,
path: '/somebot/v1/hello/',
} as const;

public override middleware: Middleware[] = [];

public constructor(private readonly prisma: PrismaClient) {
super();
}

public handle(req: Request, res: Response) {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ hello: 'world' }));
}
}
1 change: 1 addition & 0 deletions packages/api/src/routes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as GetHelloRoute } from './helloWorld.js';
Loading

0 comments on commit 7f9419f

Please sign in to comment.