Initial code
This commit is contained in:
parent
f4a1afe71b
commit
c6d3e066c9
21 changed files with 2446 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -130,3 +130,5 @@ dist
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
|
||||||
|
/src/generated/prisma
|
||||||
|
|
|
||||||
15
docker-compose.yml
Normal file
15
docker-compose.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:18
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: tetheruser
|
||||||
|
POSTGRES_PASSWORD: 2914400844
|
||||||
|
POSTGRES_DB: tetherdb
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
1
env
Normal file
1
env
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
DATABASE_URL="postgresql://tetheruser:password@localhost:5432/tetherdb"
|
||||||
2091
package-lock.json
generated
Normal file
2091
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
31
package.json
Normal file
31
package.json
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"name": "tether",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Communication server using the Nexlink protocol",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.aslan2142.space/aslan/tether"
|
||||||
|
},
|
||||||
|
"license": "GPL-3.0-only",
|
||||||
|
"author": "",
|
||||||
|
"type": "module",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "npx tsc",
|
||||||
|
"start": "npx tsc && node --env-file=.env dist/index.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^25.0.3",
|
||||||
|
"@types/pg": "^8.16.0",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"prisma": "^7.2.0",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/adapter-pg": "^7.2.0",
|
||||||
|
"@prisma/client": "^7.2.0",
|
||||||
|
"fastify": "^5.6.2",
|
||||||
|
"pg": "^8.16.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
14
prisma.config.ts
Normal file
14
prisma.config.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// This file was generated by Prisma, and assumes you have installed the following:
|
||||||
|
// npm install --save-dev prisma dotenv
|
||||||
|
import "dotenv/config";
|
||||||
|
import { defineConfig } from "prisma/config";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
schema: "prisma/schema.prisma",
|
||||||
|
migrations: {
|
||||||
|
path: "prisma/migrations",
|
||||||
|
},
|
||||||
|
datasource: {
|
||||||
|
url: process.env["DATABASE_URL"],
|
||||||
|
},
|
||||||
|
});
|
||||||
11
prisma/migrations/20251223013400_init/migration.sql
Normal file
11
prisma/migrations/20251223013400_init/migration.sql
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "User" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"email" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||||
89
prisma/migrations/20251223022822_base/migration.sql
Normal file
89
prisma/migrations/20251223022822_base/migration.sql
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- The primary key for the `User` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||||
|
- A unique constraint covering the columns `[id]` on the table `User` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
- A unique constraint covering the columns `[name]` on the table `User` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "User" DROP CONSTRAINT "User_pkey",
|
||||||
|
ADD COLUMN "admin" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
ADD COLUMN "communityId" TEXT,
|
||||||
|
ADD COLUMN "description" TEXT,
|
||||||
|
ADD COLUMN "lastLogin" TIMESTAMP(3),
|
||||||
|
ADD COLUMN "passwordHash" TEXT,
|
||||||
|
ADD COLUMN "registerDate" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
ALTER COLUMN "id" DROP DEFAULT,
|
||||||
|
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||||
|
ALTER COLUMN "email" DROP NOT NULL,
|
||||||
|
ADD CONSTRAINT "User_pkey" PRIMARY KEY ("id");
|
||||||
|
DROP SEQUENCE "User_id_seq";
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Community" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Community_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Channel" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"name" TEXT,
|
||||||
|
"communityId" TEXT,
|
||||||
|
|
||||||
|
CONSTRAINT "Channel_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Role" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"name" TEXT,
|
||||||
|
"communityId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Role_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Session" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Community_id_key" ON "Community"("id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Community_name_key" ON "Community"("name");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Channel_id_key" ON "Channel"("id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Role_id_key" ON "Role"("id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Session_id_key" ON "Session"("id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_id_key" ON "User"("id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_name_key" ON "User"("name");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Channel" ADD CONSTRAINT "Channel_communityId_fkey" FOREIGN KEY ("communityId") REFERENCES "Community"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Role" ADD CONSTRAINT "Role_communityId_fkey" FOREIGN KEY ("communityId") REFERENCES "Community"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "User" ADD CONSTRAINT "User_communityId_fkey" FOREIGN KEY ("communityId") REFERENCES "Community"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
17
prisma/migrations/20251223024429_username/migration.sql
Normal file
17
prisma/migrations/20251223024429_username/migration.sql
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `name` on the `User` table. All the data in the column will be lost.
|
||||||
|
- A unique constraint covering the columns `[username]` on the table `User` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
- Added the required column `username` to the `User` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropIndex
|
||||||
|
DROP INDEX "User_name_key";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "User" DROP COLUMN "name",
|
||||||
|
ADD COLUMN "username" TEXT NOT NULL;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
|
||||||
3
prisma/migrations/migration_lock.toml
Normal file
3
prisma/migrations/migration_lock.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (e.g., Git)
|
||||||
|
provider = "postgresql"
|
||||||
52
prisma/schema.prisma
Normal file
52
prisma/schema.prisma
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client"
|
||||||
|
output = "../src/generated/prisma"
|
||||||
|
engineType = "client"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "postgresql"
|
||||||
|
}
|
||||||
|
|
||||||
|
model Community {
|
||||||
|
id String @id @unique @default(uuid())
|
||||||
|
name String @unique
|
||||||
|
members User[]
|
||||||
|
Channel Channel[]
|
||||||
|
Role Role[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model Channel {
|
||||||
|
id String @id @unique @default(uuid())
|
||||||
|
name String?
|
||||||
|
community Community? @relation(fields: [communityId], references: [id])
|
||||||
|
communityId String?
|
||||||
|
}
|
||||||
|
|
||||||
|
model Role {
|
||||||
|
id String @id @unique @default(uuid())
|
||||||
|
name String?
|
||||||
|
community Community @relation(fields: [communityId], references: [id])
|
||||||
|
communityId String
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String @id @unique @default(uuid())
|
||||||
|
username String @unique
|
||||||
|
email String? @unique
|
||||||
|
passwordHash String?
|
||||||
|
description String?
|
||||||
|
admin Boolean @default(false)
|
||||||
|
registerDate DateTime @default(now())
|
||||||
|
lastLogin DateTime?
|
||||||
|
Community Community? @relation(fields: [communityId], references: [id])
|
||||||
|
communityId String?
|
||||||
|
Session Session[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model Session {
|
||||||
|
id String @id @unique @default(uuid())
|
||||||
|
owner User @relation(fields: [userId], references: [id])
|
||||||
|
token String
|
||||||
|
userId String
|
||||||
|
}
|
||||||
4
src/config.json
Normal file
4
src/config.json
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"port": 3012,
|
||||||
|
"db": "db.json"
|
||||||
|
}
|
||||||
3
src/config.ts
Normal file
3
src/config.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import config from "./config.json" with { type: "json" };
|
||||||
|
|
||||||
|
export { config };
|
||||||
2
src/controllers/test/index.ts
Normal file
2
src/controllers/test/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./test.js";
|
||||||
|
export * from "./routes.js";
|
||||||
8
src/controllers/test/routes.ts
Normal file
8
src/controllers/test/routes.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { type FastifyInstance } from "fastify";
|
||||||
|
import * as controller from "./test.js";
|
||||||
|
|
||||||
|
const testRoutes = async (fastify: FastifyInstance) => {
|
||||||
|
fastify.get("/test", controller.test);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { testRoutes };
|
||||||
10
src/controllers/test/test.ts
Normal file
10
src/controllers/test/test.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { type FastifyReply, type FastifyRequest } from "fastify";
|
||||||
|
import { testdb } from "../../store/store.js";
|
||||||
|
|
||||||
|
const test = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
testdb();
|
||||||
|
|
||||||
|
return [{ name: "Alice" }];
|
||||||
|
};
|
||||||
|
|
||||||
|
export { test };
|
||||||
15
src/index.ts
Normal file
15
src/index.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { config } from "./config.js";
|
||||||
|
|
||||||
|
import Fastify from "fastify";
|
||||||
|
import { testRoutes } from "./controllers/test/routes.js";
|
||||||
|
|
||||||
|
const app = Fastify({
|
||||||
|
logger: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
app.register(testRoutes);
|
||||||
|
|
||||||
|
app.listen({ port: config.port }, (err, address) => {
|
||||||
|
if (err) throw err;
|
||||||
|
console.log(`Server is now listening on ${address}`);
|
||||||
|
});
|
||||||
2
src/store/index.ts
Normal file
2
src/store/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./store.js";
|
||||||
|
export * from "./types.js";
|
||||||
27
src/store/store.ts
Normal file
27
src/store/store.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { PrismaClient } from "../generated/prisma/client.js";
|
||||||
|
|
||||||
|
import { PrismaPg } from "@prisma/adapter-pg";
|
||||||
|
import { Pool } from "pg";
|
||||||
|
|
||||||
|
const connectionString = process.env.DATABASE_URL;
|
||||||
|
|
||||||
|
const pool = new Pool({ connectionString });
|
||||||
|
const adapter = new PrismaPg(pool);
|
||||||
|
|
||||||
|
const prisma = new PrismaClient({ adapter });
|
||||||
|
|
||||||
|
async function testdb() {
|
||||||
|
const test = await prisma.user.findMany();
|
||||||
|
/*
|
||||||
|
const user = await prisma.user.create({
|
||||||
|
data: { name: "Alice", email: `alice${Math.random()}@example.com` },
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Created user:", user);
|
||||||
|
|
||||||
|
const test = await prisma.user.findMany();
|
||||||
|
console.log(test);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
export { testdb };
|
||||||
3
src/store/types.ts
Normal file
3
src/store/types.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface IState {}
|
||||||
|
|
||||||
|
export { type IState };
|
||||||
46
tsconfig.json
Normal file
46
tsconfig.json
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
// Visit https://aka.ms/tsconfig to read more about this file
|
||||||
|
"compilerOptions": {
|
||||||
|
// File Layout
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./dist",
|
||||||
|
|
||||||
|
// Environment Settings
|
||||||
|
// See also https://aka.ms/tsconfig/module
|
||||||
|
"module": "nodenext",
|
||||||
|
"target": "esnext",
|
||||||
|
// For nodejs:
|
||||||
|
// "lib": ["esnext"],
|
||||||
|
"types": ["node"],
|
||||||
|
// and npm install -D @types/node
|
||||||
|
|
||||||
|
// Other Outputs
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
|
||||||
|
// Stricter Typechecking Options
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
|
|
||||||
|
// Style Options
|
||||||
|
// "noImplicitReturns": true,
|
||||||
|
// "noImplicitOverride": true,
|
||||||
|
// "noUnusedLocals": true,
|
||||||
|
// "noUnusedParameters": true,
|
||||||
|
// "noFallthroughCasesInSwitch": true,
|
||||||
|
// "noPropertyAccessFromIndexSignature": true,
|
||||||
|
|
||||||
|
// Recommended Options
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noUncheckedSideEffectImports": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "prisma.config.ts", "prisma/**", "dist"],
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue