Compare commits

...

3 Commits

37 changed files with 7303 additions and 86 deletions

View File

@@ -0,0 +1 @@
{"files":{"packages/ui/.turbo/turbo-typecheck.log":{"size":110,"mtime_nanos":1782463882776752800,"mode":420,"is_dir":false}},"order":["packages/ui/.turbo/turbo-typecheck.log"]}

View File

@@ -0,0 +1 @@
{"hash":"1bb9376dadaf6981","duration":3041,"sha":"8d659317b9d990b14324262928aa78e4e15fa4b6","dirty_hash":"fa9510cea9388d4bc05912f5175c0d4e7a04f11461edc6bd345dc3b51e6b0716"}

BIN
.turbo/cache/1bb9376dadaf6981.tar.zst vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
{"files":{"packages/config/dist/index.d.ts":{"size":1874,"mtime_nanos":1782463696518849500,"mode":420,"is_dir":false},"packages/config/dist/index.js":{"size":3043,"mtime_nanos":1782463901598335900,"mode":420,"is_dir":false},"packages/config/dist/index.js.map":{"size":3214,"mtime_nanos":1782463901597337500,"mode":420,"is_dir":false},"packages/config/dist/index.d.ts.map":{"size":521,"mtime_nanos":1782463901632066900,"mode":420,"is_dir":false},"packages/config/.turbo/turbo-build.log":{"size":105,"mtime_nanos":1782463901731813200,"mode":420,"is_dir":false},"packages/config/dist":{"size":0,"mtime_nanos":0,"mode":0,"is_dir":true}},"order":["packages/config/.turbo/turbo-build.log","packages/config/dist","packages/config/dist/index.d.ts","packages/config/dist/index.d.ts.map","packages/config/dist/index.js","packages/config/dist/index.js.map"]}

View File

@@ -0,0 +1 @@
{"hash":"355c1dee9a97e514","duration":3276,"sha":"fdf8392d42c0988594a73a8c0214d44856ec48c3","dirty_hash":"5bc41ac9379475cbd00453e982eb11026dc0bb28a119fca3c562993b73edb696"}

BIN
.turbo/cache/355c1dee9a97e514.tar.zst vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
{"files":{"apps/web/.turbo/turbo-test.log":{"size":116,"mtime_nanos":1782463899572072300,"mode":420,"is_dir":false}},"order":["apps/web/.turbo/turbo-test.log"]}

View File

@@ -0,0 +1 @@
{"hash":"61b6599d632adec7","duration":1122,"sha":"fdf8392d42c0988594a73a8c0214d44856ec48c3","dirty_hash":"5bc41ac9379475cbd00453e982eb11026dc0bb28a119fca3c562993b73edb696"}

BIN
.turbo/cache/61b6599d632adec7.tar.zst vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
{"files":{"packages/config/.turbo/turbo-typecheck.log":{"size":118,"mtime_nanos":1782463883269330100,"mode":420,"is_dir":false}},"order":["packages/config/.turbo/turbo-typecheck.log"]}

View File

@@ -0,0 +1 @@
{"hash":"6abc0126d916703e","duration":3531,"sha":"8d659317b9d990b14324262928aa78e4e15fa4b6","dirty_hash":"fa9510cea9388d4bc05912f5175c0d4e7a04f11461edc6bd345dc3b51e6b0716"}

BIN
.turbo/cache/6abc0126d916703e.tar.zst vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
{"files":{"packages/database/.turbo/turbo-typecheck.log":{"size":1438,"mtime_nanos":1782463887467109000,"mode":420,"is_dir":false}},"order":["packages/database/.turbo/turbo-typecheck.log"]}

View File

@@ -0,0 +1 @@
{"hash":"7c07bbd04939c5ca","duration":7728,"sha":"8d659317b9d990b14324262928aa78e4e15fa4b6","dirty_hash":"fa9510cea9388d4bc05912f5175c0d4e7a04f11461edc6bd345dc3b51e6b0716"}

BIN
.turbo/cache/7c07bbd04939c5ca.tar.zst vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
{"files":{"packages/contracts/.turbo/turbo-typecheck.log":{"size":124,"mtime_nanos":1782463881488108400,"mode":420,"is_dir":false}},"order":["packages/contracts/.turbo/turbo-typecheck.log"]}

View File

@@ -0,0 +1 @@
{"hash":"80b11947ece0af90","duration":1747,"sha":"8d659317b9d990b14324262928aa78e4e15fa4b6","dirty_hash":"fa9510cea9388d4bc05912f5175c0d4e7a04f11461edc6bd345dc3b51e6b0716"}

BIN
.turbo/cache/80b11947ece0af90.tar.zst vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
{"files":{"packages/database/dist":{"size":0,"mtime_nanos":0,"mode":0,"is_dir":true},"packages/database/dist/index.d.ts":{"size":585,"mtime_nanos":1782463905198409500,"mode":420,"is_dir":false},"packages/database/dist/index.d.ts.map":{"size":447,"mtime_nanos":1782463905197280200,"mode":420,"is_dir":false},"packages/database/dist/index.js":{"size":962,"mtime_nanos":1782463905155282000,"mode":420,"is_dir":false},"packages/database/.turbo/turbo-build.log":{"size":552,"mtime_nanos":1782463905303835800,"mode":420,"is_dir":false},"packages/database/dist/index.js.map":{"size":617,"mtime_nanos":1782463905154791000,"mode":420,"is_dir":false}},"order":["packages/database/.turbo/turbo-build.log","packages/database/dist","packages/database/dist/index.d.ts","packages/database/dist/index.d.ts.map","packages/database/dist/index.js","packages/database/dist/index.js.map"]}

View File

@@ -0,0 +1 @@
{"hash":"a03f7958fef5192d","duration":6846,"sha":"fdf8392d42c0988594a73a8c0214d44856ec48c3","dirty_hash":"5bc41ac9379475cbd00453e982eb11026dc0bb28a119fca3c562993b73edb696"}

BIN
.turbo/cache/a03f7958fef5192d.tar.zst vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
{"files":{"packages/auth/.turbo/turbo-typecheck.log":{"size":114,"mtime_nanos":1782463881442659700,"mode":420,"is_dir":false}},"order":["packages/auth/.turbo/turbo-typecheck.log"]}

View File

@@ -0,0 +1 @@
{"hash":"eccb56f09230a2d5","duration":1701,"sha":"8d659317b9d990b14324262928aa78e4e15fa4b6","dirty_hash":"fa9510cea9388d4bc05912f5175c0d4e7a04f11461edc6bd345dc3b51e6b0716"}

BIN
.turbo/cache/eccb56f09230a2d5.tar.zst vendored Normal file

Binary file not shown.

View File

@@ -1,17 +1,39 @@
{
"name": "@hexahost/api",
"version": "0.1.0",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "tsc",
"build": "nest build",
"dev": "nest start --watch",
"start": "node dist/main.js",
"start:prod": "node dist/main.js",
"lint": "node -e \"process.exit(0)\"",
"typecheck": "tsc --noEmit",
"test": "node --test test/**/*.test.js",
"start": "node dist/main.js",
"dev": "tsc && node dist/main.js"
"test": "node --test test/**/*.test.js"
},
"dependencies": {
"@fastify/static": "^8.0.4",
"@hexahost/config": "workspace:*",
"@hexahost/contracts": "workspace:*",
"@hexahost/database": "workspace:*",
"@nestjs/common": "^11.0.7",
"@nestjs/core": "^11.0.7",
"@nestjs/platform-fastify": "^11.0.7",
"@nestjs/swagger": "^11.0.3",
"@nestjs/throttler": "^6.4.0",
"fastify": "^5.2.1",
"nestjs-pino": "^4.3.0",
"pino": "^9.6.0",
"pino-http": "^10.4.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@types/node": "^22.10.2",
"typescript": "^5.7.2"
"@hexahost/typescript-config": "workspace:*",
"@nestjs/cli": "^11.0.2",
"@nestjs/schematics": "^11.0.0",
"@types/node": "^22.10.7",
"pino-pretty": "^13.0.0",
"typescript": "^5.7.3"
}
}

View File

@@ -39,7 +39,8 @@ export class Rfc7807ExceptionFilter implements ExceptionFilter {
instance: string,
): ProblemDetails {
if (exception instanceof HttpException) {
const response = exception.getResponse();
const httpException = exception;
const response = httpException.getResponse();
if (typeof response === 'object' && response !== null) {
const body = response as Record<string, unknown>;
@@ -55,7 +56,7 @@ export class Rfc7807ExceptionFilter implements ExceptionFilter {
if (typeof body['message'] === 'string') {
return createProblemDetails({
title: exception.name,
title: httpException.name,
status,
detail: body['message'],
instance,
@@ -68,7 +69,7 @@ export class Rfc7807ExceptionFilter implements ExceptionFilter {
status,
detail: 'Request validation failed',
instance,
errors: body['message'].map((message) => ({
errors: body['message'].map((message: unknown) => ({
message: String(message),
})),
});
@@ -76,9 +77,9 @@ export class Rfc7807ExceptionFilter implements ExceptionFilter {
}
return createProblemDetails({
title: exception.name,
title: httpException.name,
status,
detail: exception.message,
detail: httpException.message,
instance,
});
}

View File

@@ -1,26 +1,48 @@
import http from "node:http";
import { randomUUID } from 'node:crypto';
const port = Number(process.env.API_PORT ?? 3001);
const appName = process.env.APP_NAME ?? "HexaHost GameCloud";
import { NestFactory } from '@nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { Logger } from 'nestjs-pino';
const server = http.createServer((req, res) => {
if (req.url === "/healthz" || req.url === "/health") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(
JSON.stringify({
status: "ok",
service: "api",
app: appName,
phase: "0",
}),
);
return;
}
import { validateConfig } from '@hexahost/config';
res.writeHead(404, { "Content-Type": "application/json" });
res.end(JSON.stringify({ status: "not_found" }));
});
import { AppModule } from './app.module';
import { Rfc7807ExceptionFilter } from './common/filters/rfc7807-exception.filter';
server.listen(port, () => {
console.log(JSON.stringify({ level: "info", msg: "api listening", port }));
});
async function bootstrap(): Promise<void> {
const config = validateConfig();
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter({
genReqId: () => randomUUID(),
requestIdHeader: 'x-request-id',
requestIdLogLabel: 'requestId',
}),
{
bufferLogs: true,
},
);
app.useLogger(app.get(Logger));
app.setGlobalPrefix('api/v1');
app.useGlobalFilters(new Rfc7807ExceptionFilter());
const swaggerConfig = new DocumentBuilder()
.setTitle(config.APP_NAME)
.setDescription('HexaHost GameCloud REST API')
.setVersion('0.0.0')
.addServer(config.API_URL)
.build();
const document = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup('api/v1/docs', app, document);
await app.listen(config.API_PORT, '0.0.0.0');
}
void bootstrap();

View File

@@ -1,13 +1,10 @@
{
"extends": "@hexahost/typescript-config/nestjs.json",
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
"outDir": "./dist",
"rootDir": "./src",
"baseUrl": "./"
},
"include": ["src/**/*"]
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "test"]
}

File diff suppressed because one or more lines are too long

View File

@@ -1,17 +1,27 @@
{
"name": "@hexahost/worker",
"version": "0.1.0",
"version": "0.0.0",
"private": true,
"main": "./dist/index.js",
"scripts": {
"build": "tsc",
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js",
"lint": "node -e \"process.exit(0)\"",
"typecheck": "tsc --noEmit",
"test": "node --test test/**/*.test.js",
"start": "node dist/main.js",
"dev": "tsc && node dist/main.js"
"test": "node --test test/**/*.test.js"
},
"dependencies": {
"@hexahost/config": "workspace:*",
"@hexahost/database": "workspace:*",
"bullmq": "^5.34.10",
"ioredis": "^5.4.2",
"pino": "^9.6.0"
},
"devDependencies": {
"@types/node": "^22.10.2",
"typescript": "^5.7.2"
"@hexahost/typescript-config": "workspace:*",
"@types/node": "^22.10.7",
"tsx": "^4.19.2",
"typescript": "^5.7.3"
}
}

View File

@@ -1,4 +1,4 @@
import { Worker, type ConnectionOptions } from 'bullmq';
import { Job, Worker, type ConnectionOptions } from 'bullmq';
import IORedis from 'ioredis';
import { validateConfig } from '@hexahost/config';
@@ -20,7 +20,7 @@ function createQueueWorker(
): Worker {
return new Worker(
queueName,
async (job) => {
async (job: Job) => {
logger.info(
{ queue: queueName, jobId: job.id, jobName: job.name },
'Processing job',
@@ -42,11 +42,11 @@ async function bootstrap(): Promise<void> {
);
for (const worker of workers) {
worker.on('completed', (job) => {
logger.info({ queue: worker.name, jobId: job.id }, 'Job completed');
worker.on('completed', (job: Job | undefined) => {
logger.info({ queue: worker.name, jobId: job?.id }, 'Job completed');
});
worker.on('failed', (job, error) => {
worker.on('failed', (job: Job | undefined, error: Error) => {
logger.error(
{ queue: worker.name, jobId: job?.id, err: error },
'Job failed',

View File

@@ -1,14 +0,0 @@
const redisUrl = process.env.REDIS_URL ?? "redis://localhost:6379";
console.log(
JSON.stringify({
level: "info",
msg: "worker started (phase 0 stub)",
redis: redisUrl.replace(/:[^:@]+@/, ":***@"),
}),
);
// Phase 0: worker process stays alive for compose; BullMQ queues land in Phase 1+
setInterval(() => {
console.log(JSON.stringify({ level: "debug", msg: "worker heartbeat" }));
}, 60_000);

View File

@@ -1,13 +1,9 @@
{
"extends": "@hexahost/typescript-config/library.json",
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "src/main.ts"]
}

View File

@@ -11,7 +11,10 @@
"build": "turbo run build",
"lint": "turbo run lint",
"typecheck": "turbo run typecheck",
"test": "turbo run test"
"test": "turbo run test",
"db:generate": "pnpm --filter @hexahost/database db:generate",
"db:migrate": "pnpm --filter @hexahost/database db:migrate",
"db:push": "pnpm --filter @hexahost/database db:push"
},
"devDependencies": {
"turbo": "^2.3.3",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

7175
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff