mirror of
https://github.com/stoatchat/service-admin-panel.git
synced 2026-07-01 21:44:47 -04:00
feat: configure project
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
antispam
|
||||
**/*.json
|
||||
@@ -0,0 +1,2 @@
|
||||
REDIS=
|
||||
MONGODB=
|
||||
@@ -1,36 +1,10 @@
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
bun run dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
production:
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
```bash
|
||||
bun run build
|
||||
bun run start
|
||||
```
|
||||
|
||||
+4
-20
@@ -2,26 +2,10 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
--background-start-rgb: 214, 219, 220;
|
||||
--background-end-rgb: 255, 255, 255;
|
||||
.hover-btn .btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
--background-start-rgb: 0, 0, 0;
|
||||
--background-end-rgb: 0, 0, 0;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
color: rgb(var(--foreground-rgb));
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
transparent,
|
||||
rgb(var(--background-end-rgb))
|
||||
)
|
||||
rgb(var(--background-start-rgb));
|
||||
.hover-btn:hover .btn {
|
||||
display: block;
|
||||
}
|
||||
|
||||
+127
-10
@@ -1,22 +1,139 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { Inter } from 'next/font/google'
|
||||
import './globals.css'
|
||||
import type { Metadata } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] })
|
||||
import "@radix-ui/themes/styles.css";
|
||||
import { Avatar, Box, Button, Card, Flex, Text, Theme } from "@radix-ui/themes";
|
||||
import {
|
||||
Cross2Icon,
|
||||
GroupIcon,
|
||||
HomeIcon,
|
||||
InfoCircledIcon,
|
||||
Link1Icon,
|
||||
LockClosedIcon,
|
||||
MagnifyingGlassIcon,
|
||||
PersonIcon,
|
||||
ReaderIcon,
|
||||
TrashIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import Link from "next/link";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Create Next App',
|
||||
description: 'Generated by create next app',
|
||||
}
|
||||
title: "Revolt Admin Panel",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>{children}</body>
|
||||
<body className={inter.className + " p-8"}>
|
||||
<Theme>
|
||||
<Flex>
|
||||
<div className="relative">
|
||||
<Flex
|
||||
gap="2"
|
||||
direction="column"
|
||||
className="fixed left-0 top-0 w-[280px] h-[100vh] p-4 overflow-y-auto"
|
||||
>
|
||||
<img
|
||||
src="https://app.revolt.chat/assets/wide.svg"
|
||||
className="invert h-8 m-4"
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<Flex gap="3" align="center">
|
||||
<Avatar
|
||||
size="3"
|
||||
src="https://s.gravatar.com/avatar/9e06b7b88685681c231eb47693300a18?size=40&default=https%3A%2F%2Fadmin.revolt.chat%2Fhonse.png"
|
||||
radius="full"
|
||||
fallback="T"
|
||||
/>
|
||||
<Box>
|
||||
<Text as="div" size="2" weight="bold">
|
||||
insert@revolt.chat
|
||||
</Text>
|
||||
<Text as="div" size="2" color="gray">
|
||||
Admin
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Card>
|
||||
|
||||
<Link href="/">
|
||||
<Button variant="solid" className="!justify-start w-full">
|
||||
<HomeIcon /> Home
|
||||
</Button>
|
||||
</Link>
|
||||
<Button variant="surface" className="!justify-start">
|
||||
<PersonIcon />
|
||||
Team Members
|
||||
</Button>
|
||||
<Button variant="surface" className="!justify-start">
|
||||
<GroupIcon />
|
||||
Permissions & Groups
|
||||
</Button>
|
||||
<Button variant="surface" className="!justify-start">
|
||||
<Link1Icon />
|
||||
Integration Settings
|
||||
</Button>
|
||||
<Link href="/reports">
|
||||
<Button variant="surface" className="!justify-start w-full">
|
||||
<ReaderIcon /> Reports & Cases
|
||||
</Button>
|
||||
</Link>
|
||||
<Button variant="surface" className="!justify-start">
|
||||
<MagnifyingGlassIcon />
|
||||
Search by ID
|
||||
</Button>
|
||||
<Button variant="surface" className="!justify-start">
|
||||
<LockClosedIcon />
|
||||
Authifier
|
||||
</Button>
|
||||
<Button variant="surface" className="!justify-start">
|
||||
<TrashIcon />
|
||||
Nuked Content
|
||||
</Button>
|
||||
<Button variant="surface" className="!justify-start">
|
||||
<InfoCircledIcon />
|
||||
About
|
||||
</Button>
|
||||
|
||||
{/* <div className="w-[100%] border-t-[1px] border-t-gray" /> */}
|
||||
|
||||
{/* {[
|
||||
"Case: Server(s) ijghhjifg",
|
||||
"Server: Balls!",
|
||||
"User: userisreal",
|
||||
].map((x, i) => (
|
||||
<Flex
|
||||
gap="2"
|
||||
key={i}
|
||||
className="overflow-hidden min-w-0 flex-shrink-0 hover-btn"
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="whitespace-nowrap text-ellipsis overflow-hidden !block !flex-shrink flex-grow"
|
||||
>
|
||||
{x}
|
||||
</Button>
|
||||
<Button variant="outline" color="tomato" className="btn">
|
||||
<Cross2Icon />
|
||||
</Button>
|
||||
</Flex>
|
||||
))} */}
|
||||
</Flex>
|
||||
</div>
|
||||
<div className="w-[260px] flex-shrink-0" />
|
||||
{children}
|
||||
</Flex>
|
||||
</Theme>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
+2
-112
@@ -1,113 +1,3 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
|
||||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
||||
Get started by editing
|
||||
<code className="font-mono font-bold">app/page.tsx</code>
|
||||
</p>
|
||||
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
|
||||
<a
|
||||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
By{' '}
|
||||
<Image
|
||||
src="/vercel.svg"
|
||||
alt="Vercel Logo"
|
||||
className="dark:invert"
|
||||
width={100}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px] z-[-1]">
|
||||
<Image
|
||||
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js Logo"
|
||||
width={180}
|
||||
height={37}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
|
||||
<a
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Docs{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Find in-depth information about Next.js features and API.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Learn{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Learn about Next.js in an interactive course with quizzes!
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Templates{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Explore starter templates for Next.js.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Deploy{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
export default function A() {
|
||||
return <div>ding</div>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { readFileSync } from "fs";
|
||||
import { Document, MongoClient } from "mongodb";
|
||||
import { resolve } from "path";
|
||||
|
||||
/**
|
||||
* Global handle shared in process
|
||||
*/
|
||||
let client: MongoClient;
|
||||
|
||||
/**
|
||||
* Fetch handle to MongoDB client
|
||||
* @returns Mongo client
|
||||
*/
|
||||
function mongo() {
|
||||
if (!client) {
|
||||
client = new MongoClient(process.env.MONGODB!);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch handle to MongoDB database
|
||||
* @param name Database name
|
||||
* @returns Database handle
|
||||
*/
|
||||
export function db(name: string = "revolt") {
|
||||
return mongo().db(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch handle to MongoDB collection
|
||||
* Uses the `revolt` database by default
|
||||
* @param name Collection name
|
||||
* @returns Collection handle
|
||||
*/
|
||||
export function col<T extends Document>(name: string) {
|
||||
return db().collection<T>(name);
|
||||
}
|
||||
|
||||
export default mongo;
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
import {
|
||||
Channel,
|
||||
Member,
|
||||
Message,
|
||||
ReportedContent,
|
||||
Server,
|
||||
User,
|
||||
} from "revolt-api";
|
||||
import { col } from ".";
|
||||
|
||||
export type CaseDocument = {
|
||||
_id: string;
|
||||
title: string;
|
||||
notes?: string;
|
||||
author: string;
|
||||
status: "Open" | "Closed";
|
||||
closed_at?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Use `safety_cases` collection
|
||||
*/
|
||||
export function cases() {
|
||||
return col<CaseDocument>("safety_cases");
|
||||
}
|
||||
|
||||
export type ReportDocument = {
|
||||
_id: string;
|
||||
author_id: string;
|
||||
content: ReportedContent;
|
||||
additional_context: string;
|
||||
case_id?: string;
|
||||
} & (
|
||||
| { status: "Created" }
|
||||
| ({
|
||||
type: "Rejected" | "Resolved";
|
||||
closed_at?: string;
|
||||
} & (
|
||||
| { type: "Rejected"; rejection_reason?: string }
|
||||
| { type: "Resolved" }
|
||||
))
|
||||
);
|
||||
|
||||
/**
|
||||
* Use `safety_reports` collection
|
||||
*/
|
||||
export function reports() {
|
||||
return col<ReportDocument>("safety_reports");
|
||||
}
|
||||
|
||||
export type SnapshotDocument = {
|
||||
_id: string;
|
||||
report_id: string;
|
||||
content:
|
||||
| ({
|
||||
_type: "Message";
|
||||
_prior_context: Message[];
|
||||
_leading_context: Message[];
|
||||
} & Message)
|
||||
| ({
|
||||
_type: "Server";
|
||||
} & Server)
|
||||
| ({ _type: "User" } & User);
|
||||
};
|
||||
|
||||
/**
|
||||
* Use `safety_snapshots` collection
|
||||
*/
|
||||
export function snapshots() {
|
||||
return col<SnapshotDocument>("safety_snapshots");
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `servers` collection
|
||||
*/
|
||||
export function servers() {
|
||||
return col<Server>("servers");
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `channels` collection
|
||||
*/
|
||||
export function channels() {
|
||||
return col<Channel>("channels");
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `users` collection
|
||||
*/
|
||||
export function users() {
|
||||
return col<User>("users");
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `server_members` collection
|
||||
*/
|
||||
export function serverMembers() {
|
||||
return col<Member>("server_members");
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `messages` collection
|
||||
*/
|
||||
export function messages() {
|
||||
return col<Message>("messages");
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `accounts` collection
|
||||
*/
|
||||
export function accounts() {
|
||||
return col<{ _id: string; email: string; disabled: boolean; spam: boolean }>(
|
||||
"accounts"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `sessions` collection
|
||||
*/
|
||||
export function sessions() {
|
||||
return col<{ _id: string; user_id: string }>("sessions");
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { RedisClientType } from "redis";
|
||||
import type { ProtocolV1 } from "revolt.js/lib/events/v1";
|
||||
|
||||
import { newRedis } from ".";
|
||||
|
||||
export abstract class RedisEventListener {
|
||||
client: RedisClientType = null!;
|
||||
subscribed = new Set<string>();
|
||||
|
||||
async init(initialTopics: string[]) {
|
||||
this.client = (await newRedis()) as RedisClientType;
|
||||
this.client.on("error", (err) =>
|
||||
console.error("Redis encountered an error:", err)
|
||||
);
|
||||
|
||||
for (const topic of initialTopics) {
|
||||
await this.client.subscribe(topic, (message) =>
|
||||
this.handle(JSON.parse(message))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async setTopics(topics: string[]) {
|
||||
const newSubscribed = new Set();
|
||||
for (const topic of topics) {
|
||||
newSubscribed.add(topic);
|
||||
this.subscribed.delete(topic);
|
||||
|
||||
if (!this.subscribed.has(topic)) {
|
||||
await this.client.subscribe(topic, (message) =>
|
||||
this.handle(JSON.parse(message))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const oldTopic of this.subscribed) {
|
||||
await this.client.unsubscribe(oldTopic);
|
||||
}
|
||||
}
|
||||
|
||||
abstract handle(event: ProtocolV1["server"]): void;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { createClient, RedisClientType } from "@redis/client";
|
||||
import type { ProtocolV1 } from "revolt.js/lib/events/v1";
|
||||
|
||||
export { RedisEventListener } from "./eventListener";
|
||||
|
||||
/**
|
||||
* Global handle shared in process
|
||||
*/
|
||||
let client: RedisClientType;
|
||||
|
||||
/**
|
||||
* Fetch handle to Redis client
|
||||
* @returns Redis client
|
||||
*/
|
||||
export async function redis() {
|
||||
if (!client) {
|
||||
client = createClient({ url: process.env.REDIS! });
|
||||
await client.connect();
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Redis client
|
||||
* @returns Redis client
|
||||
*/
|
||||
export async function newRedis() {
|
||||
const client = createClient({ url: process.env.REDIS! });
|
||||
await client.connect();
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a message to Redis
|
||||
* @param topic Topic
|
||||
* @param message Message
|
||||
*/
|
||||
export async function publish(topic: string, message: ProtocolV1["server"]) {
|
||||
(await redis()).publish(topic, JSON.stringify(message));
|
||||
}
|
||||
+26
-8
@@ -1,27 +1,45 @@
|
||||
{
|
||||
"name": "revolt-admin-panel",
|
||||
"name": "revolt-swiss-army-knife",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"dev": "nodemon --exec \"bun run build:server && NODE_EXTRA_CA_CERTS=$PWD/revolt.crt node server/.build/server/index.js\" -e ts --watch server",
|
||||
"build": "bun run build:server && bun run build:client",
|
||||
"build:server": "cd server && (rm -r .build ||:) && tsc && cd ..",
|
||||
"build:client": "next build",
|
||||
"start": "NODE_EXTRA_CA_CERTS=$PWD/revolt.crt NODE_ENV=production node server/.build/server/index.js",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@colors/colors": "^1.6.0",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/themes": "^2.0.3",
|
||||
"@tensorflow/tfjs-node": "^4.17.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"lru-cache": "^10.2.0",
|
||||
"mongodb": "^6.3.0",
|
||||
"next": "14.0.4",
|
||||
"node-cron": "^3.0.3",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"next": "14.0.4"
|
||||
"redis": "^4.6.13",
|
||||
"revolt-api": "^0.6.9",
|
||||
"revolt.js": "^7.0.0-beta.11",
|
||||
"scikitjs": "^1.24.0",
|
||||
"string-comparison": "^1.3.0",
|
||||
"ulid": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5",
|
||||
"@types/node": "^20",
|
||||
"@types/node-cron": "^3.0.11",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"autoprefixer": "^10.0.1",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.0.4",
|
||||
"nodemon": "^3.0.3",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.0.4"
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDRTCCAi2gAwIBAgIURRsMg9wuSxJa1CQQgAlu6s6Dox4wDQYJKoZIhvcNAQEL
|
||||
BQAwFDESMBAGA1UEAwwJUmV2b2x0IENBMB4XDTIzMDczMTEzMDMwNVoXDTMzMDcy
|
||||
ODEzMDMwNVowFDESMBAGA1UEAwwJUmV2b2x0IENBMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAoI5R5hlJa2C4z7Y9x3z0inmQAvGsF4WlhUejiV9l+Vfg
|
||||
NDoezvFIQwTENduuJfE+l1/7AQ21uxPpM7qG8GwzW4EVIsf6VRbnyEBtap4tlAGd
|
||||
Kj/LzUFo0ec0jkz9fCz+2MxZ19S4jiqaYFZZDquZwQYgjrwe9Mi2MLx1w8sXzoqk
|
||||
6roCiQBch4n4aoTyyPVqzrfW8fNJAWqFnt8af5NI2TTw1KBFRB8HnD7VJMTnAaTf
|
||||
0PuqP/Ql1e+KIJIuM+kXeGjMPZkLUgXpfTnHX9lPZLoTKh6zNcSSpUo/kDmLAgBQ
|
||||
B3fLQQQZFa9jaAfk+RJ0iO//PlP4Edc0izDVbSZJgQIDAQABo4GOMIGLMB0GA1Ud
|
||||
DgQWBBQZ8qaangMWbe2MdkfhCVSU200LnTBPBgNVHSMESDBGgBQZ8qaangMWbe2M
|
||||
dkfhCVSU200LnaEYpBYwFDESMBAGA1UEAwwJUmV2b2x0IENBghRFGwyD3C5LElrU
|
||||
JBCACW7qzoOjHjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B
|
||||
AQsFAAOCAQEAHEToe0tVMEXFWgXpkcWq7AkJonF87xH5HEUmEEOOgex099ZegXRh
|
||||
oV/L7JrhCb7yAWVpvNXYwMsb/ehThMYo1rWuBAUzmW1WPr+14VaJ8G+uFV7RKMLn
|
||||
W1AHjOsenm6K//0CSkOvJuvrwJ6C8N4kYQWFxJVS1lUSfeGEwLBTLNd20NHyLpgG
|
||||
c/4g7IaMLLovTK0QDD3ACmt25b9DO3FbRV5GNKnSgmMPDO9gHmzJfCjGO8hWdLjO
|
||||
BdA6P855RzZ4gcFxVvViQQ0olap/2Y5LlohQBDOuGIh5WyWezuljFtbS/zoMtTjG
|
||||
dmOACjM2WDFZnDsy1gOPvPC+PlA0p1kCbw==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1 @@
|
||||
.build
|
||||
@@ -0,0 +1,64 @@
|
||||
import { createServer } from "http";
|
||||
import { parse } from "url";
|
||||
import next from "next";
|
||||
|
||||
const dev = process.env.NODE_ENV !== "production";
|
||||
const hostname = process.env.HOST || "localhost";
|
||||
const port = parseInt(process.env.PORT || "3000");
|
||||
|
||||
const app = next({ dev, hostname, port });
|
||||
const handle = app.getRequestHandler();
|
||||
|
||||
import { bgBlue, bgGreen, bgRed, gray, red } from "@colors/colors";
|
||||
import { readdir, readFile } from "fs/promises";
|
||||
import { resolve } from "path";
|
||||
import { createLogger } from "./logger";
|
||||
|
||||
async function printVersion() {
|
||||
const { version } = JSON.parse(
|
||||
await readFile("package.json").then((f) => f.toString())
|
||||
);
|
||||
|
||||
console.log("\n");
|
||||
createLogger(bgBlue(" Revolt "))(`Swiss Army Knife v${version}`);
|
||||
}
|
||||
|
||||
async function loadModules() {
|
||||
const log = createLogger(bgRed(" Modules "));
|
||||
const modules = await readdir(resolve("server/.build/server/modules"));
|
||||
log(`Found ${modules.length} modules!`);
|
||||
|
||||
for (const moduleName of modules) {
|
||||
log(gray(`Initialising ${moduleName}`));
|
||||
require(resolve(`server/.build/server/modules/${moduleName}/index.js`));
|
||||
}
|
||||
}
|
||||
|
||||
async function startApp() {
|
||||
const log = createLogger(bgGreen(" Web "));
|
||||
await app.prepare().then(() => {
|
||||
createServer(async (req, res) => {
|
||||
try {
|
||||
// Be sure to pass `true` as the second argument to `url.parse`.
|
||||
// This tells it to parse the query portion of the URL.
|
||||
const parsedUrl = parse(req.url!, true);
|
||||
// const { pathname, query } = parsedUrl;
|
||||
|
||||
await handle(req, res, parsedUrl);
|
||||
} catch (err) {
|
||||
log(red(`Error occurred handling ${req.url}: ${err}`));
|
||||
res.statusCode = 500;
|
||||
res.end("internal server error");
|
||||
}
|
||||
})
|
||||
.once("error", (err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
})
|
||||
.listen(port, () =>
|
||||
log(`Admin Panel is ready on http://${hostname}:${port}`)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
printVersion().then(loadModules).then(startApp);
|
||||
@@ -0,0 +1,11 @@
|
||||
import { gray } from "@colors/colors";
|
||||
|
||||
/**
|
||||
* Create a logging function for a module
|
||||
* @param moduleName Module name
|
||||
* @returns Logging function
|
||||
*/
|
||||
export function createLogger(moduleName: string) {
|
||||
return (str: string) =>
|
||||
console.log(`${gray(new Date().toISOString())} ${moduleName} ${str}`);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# for now:
|
||||
**/*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "esnext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs" /* Specify what module code is generated. */,
|
||||
"rootDir": "../" /* Specify the root folder within your source files. */,
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./.build" /* Specify an output folder for all emitted files. */,
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"downlevelIteration": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
|
||||
Reference in New Issue
Block a user