refactor: break monorepo into 3 standalone services (gateway, backend, frontend)
Build & Deploy / build-and-push (backend) (push) Failing after 35s
Build & Deploy / build-and-push (discord-gateway) (push) Failing after 25s
Build & Deploy / build-and-push (proxy) (push) Failing after 25s
Build & Deploy / build-and-push (backend) (push) Failing after 35s
Build & Deploy / build-and-push (discord-gateway) (push) Failing after 25s
Build & Deploy / build-and-push (proxy) (push) Failing after 25s
- Remove pnpm workspace, moon repo, and all monorepo tooling - Delete packages/shared/, embed shared code directly into each service - Copy packages/shared/src/* -> services/backend/src/shared/ and services/discord-gateway/src/shared/ - Replace all @bete/shared imports with @/shared/ path alias - Remove @bete/shared workspace dependency from both services - Update root package.json scripts from --filter to --prefix - Rewrite Dockerfiles to build each service standalone - Clean up biome.json, .gitignore, remove root drizzle.config.ts
This commit is contained in:
@@ -8,9 +8,6 @@ public/app/
|
||||
.env.test
|
||||
logs/
|
||||
.codegraph/
|
||||
# moon
|
||||
.moon/cache
|
||||
.moon/docker
|
||||
worktrees/
|
||||
.worktrees/
|
||||
services/frontend/frontend/dist/
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
$schema: 'https://moonrepo.dev/schema/config/v2.json'
|
||||
|
||||
# Global task templates — each project must explicitly inherit via workspace.inheritedTasks
|
||||
# In moon v2, these define reusable task templates
|
||||
tasks:
|
||||
lint:
|
||||
command: biome
|
||||
args:
|
||||
- check
|
||||
- '--diagnostic-level=error'
|
||||
- .
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- 'src/**/*'
|
||||
- '*.js'
|
||||
- '*.mjs'
|
||||
- '*.ts'
|
||||
- '*.mts'
|
||||
|
||||
format:
|
||||
command: biome
|
||||
args:
|
||||
- format
|
||||
- '--write'
|
||||
- .
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- 'src/**/*'
|
||||
- '*.js'
|
||||
- '*.mjs'
|
||||
- '*.ts'
|
||||
- '*.mts'
|
||||
@@ -1,10 +0,0 @@
|
||||
$schema: 'https://moonrepo.dev/schema/config/v2.json'
|
||||
|
||||
# Moon Workspace Configuration
|
||||
projects:
|
||||
- 'services/*'
|
||||
- 'packages/*'
|
||||
|
||||
vcs:
|
||||
defaultBranch: main
|
||||
provider: github
|
||||
@@ -11,13 +11,11 @@
|
||||
"tests/**/*.ts",
|
||||
"services/**/*.ts",
|
||||
"services/**/*.tsx",
|
||||
"packages/**/*.ts",
|
||||
"*.json",
|
||||
"*.ts",
|
||||
"!vendor",
|
||||
"!.claude",
|
||||
"!services/**/dist",
|
||||
"!packages/**/dist",
|
||||
"!services/**/.next",
|
||||
"!services/**/out"
|
||||
]
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
|
||||
const databaseUrl = process.env.DATABASE_URL;
|
||||
|
||||
export default defineConfig({
|
||||
schema: "./src/database/schema.ts",
|
||||
out: "./drizzle/migrations",
|
||||
dialect: "postgresql",
|
||||
dbCredentials: databaseUrl
|
||||
? { url: databaseUrl }
|
||||
: {
|
||||
host: process.env.POSTGRES_HOST || "localhost",
|
||||
port: parseInt(process.env.POSTGRES_PORT || "5432", 10),
|
||||
user: process.env.POSTGRES_USER || "postgres",
|
||||
password: process.env.POSTGRES_PASSWORD || "",
|
||||
database: process.env.POSTGRES_DB || "moderation_bot",
|
||||
},
|
||||
});
|
||||
@@ -2,12 +2,6 @@ FROM node:22-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Build args for frontend API URLs
|
||||
ARG VITE_BE_API_URL
|
||||
ARG VITE_BE_WS_URL
|
||||
ENV VITE_BE_API_URL=${VITE_BE_API_URL}
|
||||
ENV VITE_BE_WS_URL=${VITE_BE_WS_URL}
|
||||
|
||||
# Install pnpm
|
||||
RUN npm install -g pnpm
|
||||
|
||||
@@ -18,30 +12,21 @@ RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends python3
|
||||
RUN groupadd --system app && useradd --system -g app app
|
||||
|
||||
# Copy dependency definition files first for better caching
|
||||
COPY pnpm-workspace.yaml .
|
||||
COPY pnpm-lock.yaml .
|
||||
COPY package.json .
|
||||
COPY services/backend/package.json services/backend/pnpm-lock.yaml* ./services/backend/
|
||||
|
||||
# Copy patches (pnpm patchedDependencies)
|
||||
COPY patches ./patches
|
||||
|
||||
# Copy packages (workspace dependencies)
|
||||
COPY packages/shared ./packages/shared
|
||||
# Copy service source (shared code is embedded in src/shared/)
|
||||
COPY services/backend/ ./services/backend/
|
||||
|
||||
# Copy service
|
||||
COPY services/backend ./services/backend
|
||||
|
||||
# Install dependencies with build cache
|
||||
# Install dependencies
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# Build shared workspace dependency first
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||
pnpm --filter './packages/shared' run build
|
||||
cd services/backend && pnpm install --frozen-lockfile
|
||||
|
||||
# Build backend
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||
pnpm --filter './services/backend' run build
|
||||
cd services/backend && pnpm run build
|
||||
|
||||
# Own dist + node_modules by non-root user
|
||||
RUN chown -R app:app /app
|
||||
|
||||
@@ -13,40 +13,23 @@ RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends \
|
||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||
|
||||
# Dependency manifests
|
||||
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
|
||||
COPY services/discord-gateway/package.json services/discord-gateway/pnpm-lock.yaml* ./services/discord-gateway/
|
||||
COPY patches ./patches
|
||||
COPY packages/shared/package.json ./packages/shared/package.json
|
||||
COPY services/discord-gateway/package.json ./services/discord-gateway/package.json
|
||||
|
||||
# Install ALL deps (including devDeps needed for build)
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||
pnpm install --frozen-lockfile
|
||||
cd services/discord-gateway && pnpm install --frozen-lockfile
|
||||
|
||||
# Source code
|
||||
COPY packages/shared ./packages/shared
|
||||
# Source code (shared code is embedded in src/shared/)
|
||||
COPY services/discord-gateway ./services/discord-gateway
|
||||
COPY services/discord-gateway/drizzle ./drizzle
|
||||
|
||||
# Build (combined to reduce layers)
|
||||
# Build
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||
pnpm --filter './packages/shared' run build \
|
||||
&& pnpm --filter './services/discord-gateway' run build \
|
||||
cd services/discord-gateway && pnpm run build \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create production-only deployment (no devDeps)
|
||||
RUN pnpm deploy --legacy --filter '@bete/discord-gateway' /tmp/deploy \
|
||||
&& rm -rf /tmp/deploy/node_modules/.pnpm/@biomejs+biome@* \
|
||||
/tmp/deploy/node_modules/.pnpm/@biomejs+cli-linux-x64@* \
|
||||
/tmp/deploy/node_modules/.pnpm/typescript@* \
|
||||
/tmp/deploy/node_modules/.pnpm/drizzle-kit@* \
|
||||
/tmp/deploy/node_modules/.pnpm/vitest@* \
|
||||
/tmp/deploy/node_modules/.pnpm/esbuild@* \
|
||||
/tmp/deploy/node_modules/.pnpm/tsx@* \
|
||||
/tmp/deploy/node_modules/.pnpm/@types* \
|
||||
/tmp/deploy/node_modules/.pnpm/@rolldown* \
|
||||
/tmp/deploy/node_modules/.pnpm/@vitest*
|
||||
|
||||
# ---- Stage 2: Runtime (minimal) ----
|
||||
FROM node:22-slim
|
||||
|
||||
@@ -57,11 +40,10 @@ RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends \
|
||||
ffmpeg ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy production-only artifacts from deploy
|
||||
COPY --from=builder /tmp/deploy/node_modules ./node_modules
|
||||
COPY --from=builder /tmp/deploy/package.json ./package.json
|
||||
COPY --from=builder /app/packages/shared/dist ./packages/shared/dist
|
||||
# Copy built artifacts
|
||||
COPY --from=builder /app/services/discord-gateway/dist ./services/discord-gateway/dist
|
||||
COPY --from=builder /app/services/discord-gateway/node_modules ./services/discord-gateway/node_modules
|
||||
COPY --from=builder /app/services/discord-gateway/package.json ./services/discord-gateway/package.json
|
||||
COPY --from=builder /app/drizzle ./drizzle
|
||||
|
||||
# Create recordings dir and set ownership
|
||||
|
||||
@@ -11,20 +11,14 @@ RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends \
|
||||
python3 make g++ && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy dependency manifests first for layer caching
|
||||
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
|
||||
COPY packages/shared/package.json ./packages/shared/package.json
|
||||
COPY services/frontend/package.json ./services/frontend/package.json
|
||||
COPY services/frontend/package.json services/frontend/pnpm-lock.yaml* ./services/frontend/
|
||||
COPY services/frontend/tsconfig.json ./services/frontend/tsconfig.json
|
||||
|
||||
# Copy patches (pnpm patchedDependencies)
|
||||
COPY patches/ ./patches/
|
||||
|
||||
# Install dependencies (frontend + shared)
|
||||
# Install frontend dependencies (standalone, no shared workspace dep)
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||
pnpm install --no-frozen-lockfile --filter './packages/shared' --filter './services/frontend'
|
||||
cd services/frontend && pnpm install --no-frozen-lockfile
|
||||
|
||||
# Copy source code
|
||||
COPY packages/shared/ ./packages/shared/
|
||||
COPY services/frontend/ ./services/frontend/
|
||||
|
||||
# Pass API/WS URLs as build args
|
||||
@@ -33,11 +27,9 @@ ARG VITE_BE_WS_URL
|
||||
ENV VITE_BE_API_URL=${VITE_BE_API_URL}
|
||||
ENV VITE_BE_WS_URL=${VITE_BE_WS_URL}
|
||||
|
||||
# Build shared lib first, then frontend static export
|
||||
# Build frontend static export
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||
pnpm --filter './packages/shared' run build
|
||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||
pnpm --filter frontend run build
|
||||
cd services/frontend && pnpm run build
|
||||
|
||||
# ---- Stage 2: Nginx ----
|
||||
FROM nginx:alpine
|
||||
|
||||
+11
-18
@@ -1,31 +1,24 @@
|
||||
{
|
||||
"name": "discord-voice-recorder",
|
||||
"name": "bete-monorepo",
|
||||
"version": "1.0.0",
|
||||
"description": "Discord bot that joins a voice channel and records audio",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@11.1.3",
|
||||
"private": true,
|
||||
"description": "Bete Discord Moderation Services — standalone services in one repo",
|
||||
"scripts": {
|
||||
"dev:backend": "pnpm --filter './services/backend' run dev",
|
||||
"dev:discord-gateway": "pnpm --filter './services/discord-gateway' run dev",
|
||||
"dev:web": "pnpm --filter './services/frontend' run dev",
|
||||
"build:web": "pnpm --filter './services/frontend' run build",
|
||||
"typecheck:web": "pnpm --filter './services/frontend' run build",
|
||||
"build:backend": "pnpm --filter './services/backend' run build",
|
||||
"build:discord-gateway": "pnpm --filter './services/discord-gateway' run build",
|
||||
"typecheck": "pnpm -r run typecheck",
|
||||
"dev:backend": "pnpm --prefix services/backend dev",
|
||||
"dev:discord-gateway": "pnpm --prefix services/discord-gateway dev",
|
||||
"dev:web": "pnpm --prefix services/frontend dev",
|
||||
"build:web": "pnpm --prefix services/frontend build",
|
||||
"build:backend": "pnpm --prefix services/backend build",
|
||||
"build:discord-gateway": "pnpm --prefix services/discord-gateway build",
|
||||
"typecheck": "pnpm --prefix services/backend typecheck && pnpm --prefix services/discord-gateway typecheck",
|
||||
"lint": "biome check --diagnostic-level=error .",
|
||||
"format": "biome format --write .",
|
||||
"test": "pnpm -r run test",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"db:migrate": "drizzle-kit migrate",
|
||||
"db:studio": "drizzle-kit studio",
|
||||
"test": "pnpm --prefix services/backend test && pnpm --prefix services/discord-gateway test",
|
||||
"db:truncate": "psql \"$DATABASE_URL\" -f scripts/truncate-all.sql",
|
||||
"install:yt-dlp": "sh scripts/install-yt-dlp.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.5.5",
|
||||
"drizzle-kit": "^0.31.10",
|
||||
"tsx": "^4.22.2",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
$schema: 'https://moonrepo.dev/schema/config/v2.json'
|
||||
|
||||
language: typescript
|
||||
|
||||
tasks:
|
||||
typecheck:
|
||||
command: tsc --noEmit
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
- tsconfig.json
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"name": "@bete/shared",
|
||||
"version": "1.0.0",
|
||||
"description": "Shared utilities, types, and errors for Bete microservices",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./config": "./dist/config/index.js",
|
||||
"./database/pool": "./dist/database/pool.js",
|
||||
"./database/schema": "./dist/database/schema.js",
|
||||
"./database/init": "./dist/database/init.js",
|
||||
"./errors": "./dist/errors/index.js",
|
||||
"./logger": "./dist/logger/index.js",
|
||||
"./moderation-types": "./dist/moderation-types.js",
|
||||
"./redis-channels": "./dist/redis-channels.js",
|
||||
"./utils": "./dist/utils/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"drizzle-orm": "^0.45.2",
|
||||
"pg": "^8.13.0",
|
||||
"pino": "^9.0.0",
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.9.0",
|
||||
"@types/pg": "^8.11.0",
|
||||
"pino-pretty": "^13.1.3",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020"],
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "bundler"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
packages:
|
||||
- services/*
|
||||
- packages/*
|
||||
|
||||
allowBuilds:
|
||||
'@discordjs/opus': true
|
||||
'@lng2004/node-datachannel': true
|
||||
esbuild: true
|
||||
node-av: true
|
||||
node-crc: true
|
||||
sharp: true
|
||||
zeromq: true
|
||||
|
||||
minimumReleaseAgeExclude:
|
||||
- '@types/node@25.9.0'
|
||||
- pg-cloudflare@1.4.0
|
||||
- pg-connection-string@2.13.0
|
||||
- pg-pool@3.14.0
|
||||
- pg-protocol@1.14.0
|
||||
- pg@8.21.0
|
||||
- tsx@4.22.2
|
||||
- '@next/env@16.2.12'
|
||||
- '@next/swc-darwin-arm64@16.2.12'
|
||||
- '@next/swc-darwin-x64@16.2.12'
|
||||
- '@next/swc-linux-arm64-gnu@16.2.12'
|
||||
- '@next/swc-linux-arm64-musl@16.2.12'
|
||||
- '@next/swc-linux-x64-gnu@16.2.12'
|
||||
- '@next/swc-linux-x64-musl@16.2.12'
|
||||
- '@next/swc-win32-arm64-msvc@16.2.12'
|
||||
- '@next/swc-win32-x64-msvc@16.2.12'
|
||||
- lucide-react@1.27.0
|
||||
- next@16.2.12
|
||||
- shadcn@4.15.0
|
||||
|
||||
onlyBuiltDependencies:
|
||||
- '@discordjs/opus'
|
||||
- '@lng2004/node-datachannel'
|
||||
- esbuild
|
||||
- node-av
|
||||
- sharp
|
||||
- zeromq
|
||||
|
||||
patchedDependencies:
|
||||
node-crc@4.0.0: patches/node-crc@4.0.0.patch
|
||||
@@ -1,48 +0,0 @@
|
||||
# Backend service - Discord moderation monitoring
|
||||
language: typescript
|
||||
|
||||
tasks:
|
||||
dev:
|
||||
command: tsx watch src/index.ts
|
||||
preset: server
|
||||
|
||||
build:
|
||||
command: tsc
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
- tsconfig.json
|
||||
outputs:
|
||||
- dist
|
||||
|
||||
typecheck:
|
||||
command: tsc --noEmit
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
- tsconfig.json
|
||||
|
||||
lint:
|
||||
command: biome check --diagnostic-level=error .
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
|
||||
format:
|
||||
command: biome format --write .
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
|
||||
test:
|
||||
command: vitest run
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
- tests
|
||||
- tsconfig.json
|
||||
@@ -14,7 +14,6 @@
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bete/shared": "workspace:*",
|
||||
"@discordjs/voice": "^0.19.2",
|
||||
"axios": "^1.16.1",
|
||||
"dotenv": "^17.4.2",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import express, {
|
||||
type Express,
|
||||
type NextFunction,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createServer, type Server } from "node:http";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../shared/config/index.js";
|
||||
import { initializeDatabase } from "../shared/database/index.js";
|
||||
import { startRedisBridge } from "../ws/redis-bridge.js";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Server } from "node:http";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { startHttpServer } from "./http/server.js";
|
||||
import { closeDatabase } from "./shared/database/index.js";
|
||||
import { stopCommandBridge } from "./shared/redis/index.js";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { pgMessagesTable } from "@bete/shared";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { pgMessagesTable } from "../../shared/index.js";
|
||||
import { createChildLogger } from "../../shared/logger/index.js";
|
||||
import { and, desc, eq, ilike, type SQL } from "drizzle-orm";
|
||||
import { getDatabase } from "../../shared/database/index.js";
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response, Router } from "express";
|
||||
import express from "express";
|
||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/index.js";
|
||||
import type { AnalysisSearchQuery } from "./analysis.repository.js";
|
||||
import { analysisRepository } from "./analysis.repository.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response } from "express";
|
||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||
import { chatbotService } from "./chatbot.service.js";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { pgChatbotMessagesTable, pgMessagesTable } from "@bete/shared";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { pgChatbotMessagesTable, pgMessagesTable } from "../../shared/index.js";
|
||||
import { createChildLogger } from "../../shared/logger/index.js";
|
||||
import { and, desc, eq, type SQL, sql } from "drizzle-orm";
|
||||
import { getDatabase } from "../../shared/database/index.js";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/index.js";
|
||||
import type {
|
||||
ChatbotContext,
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
pgUserProfilesTable,
|
||||
pgUserReputationsTable,
|
||||
pgVoiceRecordingsTable,
|
||||
} from "@bete/shared";
|
||||
} from "../../shared/index.js";
|
||||
import type { SQL } from "drizzle-orm";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { getDatabase } from "../../shared/database/index.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response, Router } from "express";
|
||||
import express from "express";
|
||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { dashboardRepository } from "./dashboard.repository.js";
|
||||
|
||||
const logger = createChildLogger("dashboard.service");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { getDatabase } from "../../shared/database/index.js";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response, Router } from "express";
|
||||
import express from "express";
|
||||
import { asyncHandler, validateBody } from "../../shared/middlewares/index.js";
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
COMMAND_MEDIA_STOP,
|
||||
COMMAND_MEDIA_VOLUME,
|
||||
MEDIA_STATUS_KEY,
|
||||
} from "@bete/shared";
|
||||
} from "../../shared/index.js";
|
||||
import {
|
||||
createChildLogger,
|
||||
tryCommandThenFallback,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response } from "express";
|
||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||
import { messageQuerySchema } from "./messages.schema.js";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { PageResult } from "@bete/shared";
|
||||
import { pgAttachmentsTable, pgMessagesTable } from "@bete/shared";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import type { PageResult } from "../../shared/index.js";
|
||||
import { pgAttachmentsTable, pgMessagesTable } from "../../shared/index.js";
|
||||
import { createChildLogger } from "../../shared/logger/index.js";
|
||||
import {
|
||||
and,
|
||||
desc,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response, Router } from "express";
|
||||
import express from "express";
|
||||
import { asyncHandler, validateBody } from "../../shared/middlewares/index.js";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NotFoundError, ValidationError } from "@bete/shared/errors";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { NotFoundError, ValidationError } from "@/shared/errors/index";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { messagesRepository } from "./messages.repository.js";
|
||||
import type { MessageQuery } from "./messages.schema.js";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response, Router } from "express";
|
||||
import express from "express";
|
||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { pgVoiceRecordingsTable } from "@bete/shared";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { pgVoiceRecordingsTable } from "../../shared/index.js";
|
||||
import { createChildLogger } from "../../shared/logger/index.js";
|
||||
import { and, desc, eq, lt, type SQL } from "drizzle-orm";
|
||||
import { getDatabase } from "../../shared/database/index.js";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response, Router } from "express";
|
||||
import express from "express";
|
||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { getDatabase } from "../../shared/database/index.js";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response } from "express";
|
||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||
import { publishCommandNoReply } from "../../shared/redis/index.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Request, Response, Router } from "express";
|
||||
import express from "express";
|
||||
import { asyncHandler, validateBody } from "../../shared/middlewares/index.js";
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
type CommandReply,
|
||||
pgMessagesTable,
|
||||
VOICE_STATUS_KEY,
|
||||
} from "@bete/shared";
|
||||
} from "../../shared/index.js";
|
||||
import { eq } from "drizzle-orm";
|
||||
import {
|
||||
createChildLogger,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CommandReply } from "@bete/shared";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import type { CommandReply } from "./index.js";
|
||||
import { createChildLogger } from "./logger/index.js";
|
||||
|
||||
export { createChildLogger };
|
||||
|
||||
|
||||
@@ -1,4 +1,311 @@
|
||||
import "dotenv/config";
|
||||
import { config as sharedConfig } from "@bete/shared/config";
|
||||
/**
|
||||
* Unified configuration schema shared by all services.
|
||||
*
|
||||
* This is the single source of truth for all environment variables.
|
||||
* Individual services re-export from here; they do NOT define their own schemas.
|
||||
*/
|
||||
|
||||
export const config = sharedConfig;
|
||||
import { z } from "zod";
|
||||
import { ConfigError } from "../errors/index.js";
|
||||
|
||||
export const configSchema = z
|
||||
.object({
|
||||
// ── Discord ──────────────────────────────────────────────────────────
|
||||
DISCORD_TOKEN: z
|
||||
.string()
|
||||
.min(1, "DISCORD_TOKEN is required")
|
||||
.transform((value) => value.replace(/^("|')|(?:("|'))$/g, "")),
|
||||
MONITOR_GUILD_IDS: z
|
||||
.string()
|
||||
.default("")
|
||||
.transform((v) => v.split(",").filter(Boolean)),
|
||||
MONITOR_GUILD_ID: z.string().min(1).optional(),
|
||||
TEXT_GUILD_ID: z.string().min(1).optional(),
|
||||
TEXT_CHANNEL_ID: z.string().min(1).optional(),
|
||||
EXCLUDED_CHANNEL_IDS: z
|
||||
.string()
|
||||
.default("")
|
||||
.transform((v) => v.split(",").filter(Boolean))
|
||||
.describe("Channel IDs to exclude from capture"),
|
||||
EXCLUDED_THREAD_IDS: z
|
||||
.string()
|
||||
.default("")
|
||||
.transform((v) => v.split(",").filter(Boolean))
|
||||
.describe("Thread IDs to exclude from capture"),
|
||||
|
||||
// ── Legacy voice ─────────────────────────────────────────────────────
|
||||
VOICE_GUILD_ID: z.string().min(1).optional(),
|
||||
VOICE_CHANNEL_ID: z.string().min(1).optional(),
|
||||
|
||||
// ── Recording ────────────────────────────────────────────────────────
|
||||
RECORDINGS_DIR: z.string().default("./recordings"),
|
||||
RECORDING_SEGMENT_MS: z.coerce.number().positive().default(5000),
|
||||
|
||||
// ── Decoder ──────────────────────────────────────────────────────────
|
||||
DECODER_ROTATE_MS: z.coerce.number().positive().default(5000),
|
||||
DECODER_COOLDOWN_MS: z.coerce.number().positive().default(30000),
|
||||
|
||||
// ── Audio ────────────────────────────────────────────────────────────
|
||||
AUDIO_STREAM_SILENCE_DURATION_MS: z.coerce
|
||||
.number()
|
||||
.positive()
|
||||
.default(3000),
|
||||
PACKET_FILTER_MIN_SIZE: z.coerce.number().positive().default(8),
|
||||
OPUS_FRAME_SIZE: z.coerce.number().positive().default(960),
|
||||
AUDIO_SAMPLE_RATE: z.coerce.number().positive().default(48000),
|
||||
AUDIO_CHANNELS: z.coerce.number().positive().default(2),
|
||||
AVATAR_SIZE: z.coerce.number().positive().default(64),
|
||||
|
||||
// ── Server ───────────────────────────────────────────────────────────
|
||||
WEBSERVER_PORT: z.coerce.number().positive().default(3001),
|
||||
NODE_ENV: z
|
||||
.enum(["development", "production", "test"])
|
||||
.default("development"),
|
||||
LOG_LEVEL: z
|
||||
.enum(["error", "warn", "info", "http", "verbose", "debug", "silly"])
|
||||
.default("info"),
|
||||
VERBOSE: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(false),
|
||||
ADMIN_PASSWORD: z.string().default("admin123"),
|
||||
WEBHOOK_URLS: z
|
||||
.string()
|
||||
.default("")
|
||||
.transform((v) => v.split(",").filter(Boolean)),
|
||||
WEBHOOK_EVENTS: z
|
||||
.string()
|
||||
.default("message_flagged,auto_deleted,high_severity")
|
||||
.transform((v) => v.split(",").filter(Boolean)),
|
||||
METRICS_PORT: z.coerce.number().positive().default(9090),
|
||||
|
||||
// ── Database (PostgreSQL) ────────────────────────────────────────────
|
||||
DATABASE_URL: z.string().optional(),
|
||||
POSTGRES_HOST: z.string().default("localhost"),
|
||||
POSTGRES_PORT: z.coerce.number().int().positive().default(5432),
|
||||
POSTGRES_USER: z.string().optional(),
|
||||
POSTGRES_PASSWORD: z.string().optional(),
|
||||
POSTGRES_DB: z.string().optional(),
|
||||
POSTGRES_POOL_MIN: z.coerce.number().int().positive().default(2),
|
||||
POSTGRES_POOL_MAX: z.coerce.number().int().positive().default(10),
|
||||
|
||||
// ── Redis ────────────────────────────────────────────────────────────
|
||||
REDIS_URL: z.string().default("redis://localhost:6379"),
|
||||
// ── Voice PCM WebSocket (direct gateway→backend, bypasses Redis) ────
|
||||
VOICE_PCM_WS_ENABLED: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(true),
|
||||
BACKEND_WS_URL: z.string().default("ws://backend:3000/ws"),
|
||||
BACKEND_WS_TOKEN: z.string().optional().default(""),
|
||||
|
||||
// ── Connection ───────────────────────────────────────────────────────
|
||||
VOICE_CONNECTION_TIMEOUT_MS: z.coerce.number().positive().default(15000),
|
||||
RECONNECT_TIMEOUT_MS: z.coerce.number().positive().default(5000),
|
||||
|
||||
// ── Attachments ─────────────────────────────────────────────────────
|
||||
TELE_UPLOAD_URL: z
|
||||
.string()
|
||||
.url()
|
||||
.default("https://upload.asepharyana.my.id/api/upload"),
|
||||
ATTACHMENT_UPLOAD_TIMEOUT_MS: z.coerce.number().positive().default(30000),
|
||||
ATTACHMENT_MAX_SIZE_MB: z.coerce.number().positive().default(100),
|
||||
ATTACHMENT_RETRY_ATTEMPTS: z.coerce.number().positive().default(3),
|
||||
BACKLOG_SYNC_HOURS: z.coerce.number().positive().default(24),
|
||||
BACKLOG_SYNC_BATCH_SIZE: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.positive()
|
||||
.max(100)
|
||||
.default(100),
|
||||
|
||||
// ── AI Analysis ─────────────────────────────────────────────────────
|
||||
AI_ANALYSIS_ENABLED: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(false),
|
||||
AI_LLM_API_KEY: z.string().optional(),
|
||||
AI_LLM_BASE_URL: z
|
||||
.string()
|
||||
.url()
|
||||
.default("https://9router.asepharyana.my.id/v1"),
|
||||
AI_LLM_MODEL: z.string().default("text"),
|
||||
AI_LLM_VISION_MODEL: z.string().optional(),
|
||||
AI_LLM_MAX_CONCURRENT: z.coerce.number().int().positive().default(5),
|
||||
AI_LLM_IMAGE_MAX_DIMENSION: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.positive()
|
||||
.default(1024),
|
||||
AI_LLM_TEXT_BATCH_SIZE: z.coerce.number().int().positive().default(20),
|
||||
AI_LLM_MEDIA_ANALYSIS_TIMEOUT_MS: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.positive()
|
||||
.default(60000),
|
||||
// ── AI Model (new unified keys) ───────────────────────────────────
|
||||
AI_MODEL_FAST_CLASSIFIER_ENABLED: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(true)
|
||||
.describe("Enable Layer 1 fast heuristic classifier"),
|
||||
AI_MODEL_LLM_TIMEOUT_MS: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.positive()
|
||||
.default(30000)
|
||||
.describe("Timeout for individual LLM moderation calls"),
|
||||
|
||||
|
||||
|
||||
// ── AI Analysis Timing ──────────────────────────────────────────────
|
||||
AI_ANALYSIS_DEBOUNCE_MS: z.coerce.number().positive().default(500),
|
||||
AI_ANALYSIS_RECOVERY_INTERVAL_MS: z.coerce
|
||||
.number()
|
||||
.positive()
|
||||
.default(15000),
|
||||
AI_ANALYSIS_ERROR_COOLDOWN_MS: z.coerce.number().positive().default(30000),
|
||||
|
||||
// ── AI Analysis Batch ───────────────────────────────────────────────
|
||||
AI_ANALYSIS_MAX_BATCH_SIZE: z.coerce.number().int().positive().default(200),
|
||||
AI_ANALYSIS_MAX_CONTEXT_TOKENS: z.coerce.number().positive().default(8000),
|
||||
AI_ANALYSIS_MAX_TARGET_TOKENS: z.coerce.number().positive().default(4000),
|
||||
AI_ANALYSIS_CONTEXT_MESSAGE_LIMIT: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.positive()
|
||||
.default(20),
|
||||
AI_ANALYSIS_PROCESSING_TIMEOUT_MS: z.coerce
|
||||
.number()
|
||||
.positive()
|
||||
.default(120000),
|
||||
AI_ANALYSIS_INDIVIDUAL_MAX_CONCURRENT: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.positive()
|
||||
.default(50),
|
||||
AI_ANALYSIS_INDIVIDUAL_CB_THRESHOLD: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.positive()
|
||||
.default(50),
|
||||
PISCINA_MAX_THREADS: z.coerce.number().int().positive().optional(),
|
||||
|
||||
// ── Voice Transcription ────────────────────────────────────────────────
|
||||
AI_VOICE_TRANSCRIPTION_ENABLED: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(false),
|
||||
|
||||
// ── OpenAI Moderation ───────────────────────────────────────────────
|
||||
OPENAI_MODERATION_API_KEY: z.string().optional(),
|
||||
OPENAI_MODERATION_BASE_URL: z
|
||||
.string()
|
||||
.url()
|
||||
.default("https://api.openai.com/v1"),
|
||||
OPENAI_MODERATION_MODEL: z.string().default("omni-moderation-latest"),
|
||||
|
||||
// ── Auto Delete ─────────────────────────────────────────────────────
|
||||
AUTO_DELETE_FLAGGED_ENABLED: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(true),
|
||||
AUTO_DELETE_FLAGGED_DRY_RUN: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(false),
|
||||
AUTO_DELETE_FLAGGED_DELAY_MS: z.coerce.number().min(0).default(0),
|
||||
AUTO_DELETE_MIN_CONFIDENCE: z.coerce.number().min(0).max(1).default(0.5),
|
||||
AUTO_DELETE_ALLOWED_SEVERITIES: z
|
||||
.string()
|
||||
.default("critical,high,medium,low"),
|
||||
AUTO_DELETE_ALLOWED_CATEGORIES: z.string().default(""),
|
||||
AUTO_DELETE_EXCLUDED_CHANNEL_IDS: z.string().default(""),
|
||||
AUTO_DELETE_EXCLUDED_USER_IDS: z.string().default(""),
|
||||
AUTO_DELETE_NOTIFY_USER: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(false),
|
||||
AUTO_DELETE_LOG_CHANNEL_ID: z.string().default(""),
|
||||
|
||||
// ── Retention ───────────────────────────────────────────────────────
|
||||
RETENTION_MESSAGES_DAYS: z.coerce.number().int().min(0).default(0),
|
||||
RETENTION_ATTACHMENTS_DAYS: z.coerce.number().int().min(0).default(0),
|
||||
RETENTION_VOICE_DAYS: z.coerce.number().int().min(0).default(0),
|
||||
RETENTION_CLEANUP_INTERVAL_MS: z.coerce
|
||||
.number()
|
||||
.positive()
|
||||
.default(24 * 60 * 60 * 1000),
|
||||
RETENTION_DRY_RUN: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(true),
|
||||
AUTO_MIGRATE_ON_STARTUP: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => v === "true")
|
||||
.default(true),
|
||||
})
|
||||
.superRefine((value, ctx) => {
|
||||
if (!value.AI_ANALYSIS_ENABLED) {
|
||||
// skip: AI analysis not enabled
|
||||
} else if (!value.AI_LLM_API_KEY) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ["AI_LLM_API_KEY"],
|
||||
message: "AI_LLM_API_KEY is required when AI_ANALYSIS_ENABLED=true",
|
||||
});
|
||||
}
|
||||
|
||||
// Validate database configuration
|
||||
if (!value.DATABASE_URL && !value.POSTGRES_HOST) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ["DATABASE_URL"],
|
||||
message: "Either DATABASE_URL or POSTGRES_HOST must be provided",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export type AppConfig = z.infer<typeof configSchema> & {
|
||||
EFFECTIVE_TEXT_GUILD_ID?: string;
|
||||
EFFECTIVE_VOICE_GUILD_ID?: string;
|
||||
EFFECTIVE_MONITOR_GUILD_IDS: string[];
|
||||
};
|
||||
|
||||
export function loadConfig(env: NodeJS.ProcessEnv = process.env): AppConfig {
|
||||
try {
|
||||
const parsed = configSchema.parse(env);
|
||||
return {
|
||||
...parsed,
|
||||
EFFECTIVE_TEXT_GUILD_ID: parsed.TEXT_GUILD_ID ?? parsed.MONITOR_GUILD_ID,
|
||||
EFFECTIVE_VOICE_GUILD_ID: parsed.VOICE_GUILD_ID,
|
||||
EFFECTIVE_MONITOR_GUILD_IDS:
|
||||
parsed.MONITOR_GUILD_IDS.length > 0
|
||||
? parsed.MONITOR_GUILD_IDS
|
||||
: parsed.MONITOR_GUILD_ID
|
||||
? [parsed.MONITOR_GUILD_ID]
|
||||
: [],
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
const messages = error.issues
|
||||
.map((e) => `${e.path.join(".")}: ${e.message}`)
|
||||
.join("\n");
|
||||
throw new ConfigError(`Configuration validation failed:\n${messages}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/** Singleton config loaded from process.env at import time. */
|
||||
export const config = loadConfig();
|
||||
|
||||
@@ -3,8 +3,8 @@ import {
|
||||
getDatabase as sharedGetDb,
|
||||
getPool as sharedGetPool,
|
||||
initializeDatabase as sharedInit,
|
||||
} from "@bete/shared/database/init";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
} from "@/shared/database/init";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../config/index.js";
|
||||
|
||||
const logger = createChildLogger("database");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "../logger/index.js";
|
||||
import { drizzle } from "drizzle-orm/node-postgres";
|
||||
import type { Pool, PoolClient } from "pg";
|
||||
import { closePool, createPoolFromConfig } from "./pool.js";
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppError, ValidationError } from "@bete/shared/errors";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { AppError, ValidationError } from "@/shared/errors/index";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { NextFunction, Request, Response } from "express";
|
||||
import type { ZodSchema } from "zod";
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
BACKEND_COMMAND_REPLY_PREFIX,
|
||||
type CommandMessage,
|
||||
type CommandReply,
|
||||
} from "@bete/shared";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
} from "../index.js";
|
||||
import { createChildLogger } from "../logger/index.js";
|
||||
import Redis from "ioredis";
|
||||
import { config } from "../config/index.js";
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* broadcastEvent("message_created", messageData);
|
||||
*/
|
||||
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
|
||||
const logger = createChildLogger("broadcast");
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DISCORD_CHANNEL_TO_WS_EVENT, DISCORD_VOICE_PCM } from "@bete/shared";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { DISCORD_CHANNEL_TO_WS_EVENT, DISCORD_VOICE_PCM } from "../shared/index.js";
|
||||
import { createChildLogger } from "../shared/logger/index.js";
|
||||
import Redis from "ioredis";
|
||||
import { config } from "../shared/config/index.js";
|
||||
import { broadcastBinary, broadcastEvent } from "./broadcast.js";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Server } from "node:http";
|
||||
import { BACKEND_COMMAND, BACKEND_VOICE_TRANSMIT } from "@bete/shared";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { BACKEND_COMMAND, BACKEND_VOICE_TRANSMIT } from "../shared/index.js";
|
||||
import { createChildLogger } from "../shared/logger/index.js";
|
||||
import { WebSocket, WebSocketServer } from "ws";
|
||||
import { config } from "../shared/config/index.js";
|
||||
import { setBroadcastFunctions } from "./broadcast.js";
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# Discord Gateway service - handles message capture, voice recording, and AI moderation
|
||||
language: typescript
|
||||
|
||||
tasks:
|
||||
dev:
|
||||
command: tsx watch src/index.ts
|
||||
preset: server
|
||||
|
||||
build:
|
||||
command: tsc
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
- tsconfig.json
|
||||
outputs:
|
||||
- dist
|
||||
|
||||
typecheck:
|
||||
command: tsc --noEmit
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
- tsconfig.json
|
||||
|
||||
lint:
|
||||
command: biome check --diagnostic-level=error .
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
|
||||
format:
|
||||
command: biome format --write .
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
|
||||
test:
|
||||
command: vitest run
|
||||
options:
|
||||
runFromWorkspaceRoot: false
|
||||
inputs:
|
||||
- src
|
||||
- tests
|
||||
- tsconfig.json
|
||||
@@ -15,7 +15,6 @@
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bete/shared": "workspace:*",
|
||||
"@discordjs/opus": "^0.10.0",
|
||||
"@discordjs/voice": "^0.19.2",
|
||||
"@snazzah/davey": "^0.1.11",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ConfigError, DatabaseError } from "@bete/shared/errors";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { ConfigError, DatabaseError } from "@/shared/errors/index";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { Client } from "discord.js-selfbot-v13";
|
||||
import { inArray, lt } from "drizzle-orm";
|
||||
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { inArray, lt } from "drizzle-orm";
|
||||
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
||||
import { config } from "../shared/config/config.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { createChildLogger } from "@bete/shared/logger";
|
||||
import type { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Client } from "discord.js-selfbot-v13";
|
||||
import type { CommandHandler } from "../modules/command-handler/commandHandler.js";
|
||||
import type { EventBroadcaster } from "../modules/event-broadcaster/index.js";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import "libsodium-wrappers";
|
||||
import "@snazzah/davey";
|
||||
import "dotenv/config";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { initializeDiscordGateway } from "./app/bootstrap.js";
|
||||
|
||||
const logger = createChildLogger("discord-gateway");
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* simpler, unified worker that combines both layers.
|
||||
*/
|
||||
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { initializeDatabase } from "../../shared/database/drizzle.js";
|
||||
import { messageStore } from "../message-capture/messageStore.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Client } from "discord.js-selfbot-v13";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import type { EventBroadcaster } from "../event-broadcaster/index.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { initializeDatabase } from "../../shared/database/drizzle.js";
|
||||
import { extractMessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import type {
|
||||
AnalysisResult,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Guild } from "discord.js-selfbot-v13";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import type { MessageRecord } from "../message-capture/types.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Client, PermissionString } from "discord.js-selfbot-v13";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { messageStore } from "../message-capture/messageStore.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Client } from "discord.js-selfbot-v13";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import type { MessageRecord } from "../message-capture/types.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { isAgeRestrictedMetadata } from "../message-capture/messageMetadata.js";
|
||||
import { messageStore } from "../message-capture/messageStore.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { messageStore } from "../message-capture/messageStore.js";
|
||||
import type { MessageRecord } from "../message-capture/types.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { getDatabase } from "../../shared/database/drizzle.js";
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { encoding_for_model as encodingForModel } from "tiktoken";
|
||||
import { formatMediaEvidenceForPrompt } from "../message-capture/messageMetadata.js";
|
||||
import type { MessageRecord } from "../message-capture/types.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { LRUCache } from "lru-cache";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { LAST_ERROR } from "./moderationState.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { and, desc, eq, sql } from "drizzle-orm";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { getDatabase } from "../../shared/database/drizzle.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { LRUCache } from "lru-cache";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { messageStore } from "../message-capture/messageStore.js";
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
*
|
||||
* Both sides now import from this module instead.
|
||||
*/
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { delay, retryWithBackoff } from "@bete/shared/utils";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { delay, retryWithBackoff } from "@/shared/utils/index";
|
||||
import type { ChatCompletion } from "openai/resources/chat/completions";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import type { AnalysisResult } from "../message-capture/types.js";
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
* defaults are maintained in one place.
|
||||
*/
|
||||
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { retryWithBackoff } from "@bete/shared/utils";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { retryWithBackoff } from "@/shared/utils/index";
|
||||
import OpenAI from "openai";
|
||||
import pLimit from "p-limit";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* analysis, and calls the LLM for a batched moderation response. Extracted from
|
||||
* moderationOrchestrator.ts.
|
||||
*/
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import type {
|
||||
AnalysisResult,
|
||||
|
||||
@@ -10,8 +10,8 @@ import { mkdtemp, readFile, rm, unlink, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createAbortControllerWithTimeout } from "@bete/shared/utils";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { createAbortControllerWithTimeout } from "@/shared/utils/index";
|
||||
import { resizeImageForVision } from "../attachment-upload/imageResizer.js";
|
||||
import type { MessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
||||
import type { AttachmentRecord } from "../message-capture/types.js";
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Orchestrates LLM-based moderation analysis — manages batch splitting,
|
||||
* parallel text+media analysis, LLM calls with retry, and cache handling.
|
||||
*/
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { extractMessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
||||
import type {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { z } from "zod";
|
||||
import type { AnalysisResult } from "../message-capture/types.js";
|
||||
import type {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { z } from "zod";
|
||||
|
||||
const log = createChildLogger("moderationSchemas");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { Client } from "discord.js-selfbot-v13";
|
||||
import { LRUCache } from "lru-cache";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* Enables full audit trail and debugging of moderation decisions.
|
||||
*/
|
||||
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type { AnalysisResult } from "../message-capture/types.js";
|
||||
|
||||
const logger = createChildLogger("response-logger");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createAbortControllerWithTimeout } from "@bete/shared/utils";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { createAbortControllerWithTimeout } from "@/shared/utils/index";
|
||||
import Redis from "ioredis";
|
||||
|
||||
const log = createChildLogger("searxng-search");
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Step 2: Real analysis text (only if not clean).
|
||||
* Extracted from moderationOrchestrator.ts.
|
||||
*/
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import type {
|
||||
AnalysisResult,
|
||||
MessageRecord,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { executeAll, executeGet } from "../../shared/database/drizzle.js";
|
||||
import { uploadToTele } from "../../shared/uploader.js";
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* searches, deduplicates short messages, splits into sub-batches, and calls
|
||||
* the LLM for analysis. Extracted from moderationOrchestrator.ts.
|
||||
*/
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import type {
|
||||
AnalysisResult,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { executeAll, executeGet } from "../../shared/database/drizzle.js";
|
||||
|
||||
const logger = createChildLogger("text-cache-store");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { resolve } from "node:dns/promises";
|
||||
import { isIP } from "node:net";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createAbortControllerWithTimeout } from "@bete/shared/utils";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { createAbortControllerWithTimeout } from "@/shared/utils/index";
|
||||
|
||||
const _log = createChildLogger("urlFetcher");
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { and, desc, eq, sql } from "drizzle-orm";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { getDatabase } from "../../shared/database/drizzle.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { getDatabase } from "../../shared/database/drizzle.js";
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { and, desc, eq } from "drizzle-orm";
|
||||
import { getDatabase } from "../../shared/database/drizzle.js";
|
||||
import {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* moderation pipeline, runs single-image vision LLM analysis with
|
||||
* multi-layer caching, and detects whether a message has media content.
|
||||
*/
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { delay } from "@bete/shared/utils";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { delay } from "@/shared/utils/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { extractMessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
||||
import type {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import { config } from "../../shared/config/config.js";
|
||||
import { uploadToTele } from "../../shared/uploader.js";
|
||||
import { messageStore } from "../message-capture/messageStore.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
import { createChildLogger } from "@/shared/logger/index";
|
||||
import sharp from "sharp";
|
||||
|
||||
const log = createChildLogger("imageResizer");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user