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
|
.env.test
|
||||||
logs/
|
logs/
|
||||||
.codegraph/
|
.codegraph/
|
||||||
# moon
|
|
||||||
.moon/cache
|
|
||||||
.moon/docker
|
|
||||||
worktrees/
|
worktrees/
|
||||||
.worktrees/
|
.worktrees/
|
||||||
services/frontend/frontend/dist/
|
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",
|
"tests/**/*.ts",
|
||||||
"services/**/*.ts",
|
"services/**/*.ts",
|
||||||
"services/**/*.tsx",
|
"services/**/*.tsx",
|
||||||
"packages/**/*.ts",
|
|
||||||
"*.json",
|
"*.json",
|
||||||
"*.ts",
|
"*.ts",
|
||||||
"!vendor",
|
"!vendor",
|
||||||
"!.claude",
|
"!.claude",
|
||||||
"!services/**/dist",
|
"!services/**/dist",
|
||||||
"!packages/**/dist",
|
|
||||||
"!services/**/.next",
|
"!services/**/.next",
|
||||||
"!services/**/out"
|
"!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
|
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
|
# Install pnpm
|
||||||
RUN npm install -g 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
|
RUN groupadd --system app && useradd --system -g app app
|
||||||
|
|
||||||
# Copy dependency definition files first for better caching
|
# Copy dependency definition files first for better caching
|
||||||
COPY pnpm-workspace.yaml .
|
COPY services/backend/package.json services/backend/pnpm-lock.yaml* ./services/backend/
|
||||||
COPY pnpm-lock.yaml .
|
|
||||||
COPY package.json .
|
|
||||||
|
|
||||||
# Copy patches (pnpm patchedDependencies)
|
# Copy patches (pnpm patchedDependencies)
|
||||||
COPY patches ./patches
|
COPY patches ./patches
|
||||||
|
|
||||||
# Copy packages (workspace dependencies)
|
# Copy service source (shared code is embedded in src/shared/)
|
||||||
COPY packages/shared ./packages/shared
|
COPY services/backend/ ./services/backend/
|
||||||
|
|
||||||
# Copy service
|
# Install dependencies
|
||||||
COPY services/backend ./services/backend
|
|
||||||
|
|
||||||
# Install dependencies with build cache
|
|
||||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||||
pnpm install --frozen-lockfile
|
cd services/backend && 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
|
|
||||||
|
|
||||||
# Build backend
|
# Build backend
|
||||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
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
|
# Own dist + node_modules by non-root user
|
||||||
RUN chown -R app:app /app
|
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}"
|
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||||
|
|
||||||
# Dependency manifests
|
# 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 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)
|
# Install ALL deps (including devDeps needed for build)
|
||||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
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
|
# Source code (shared code is embedded in src/shared/)
|
||||||
COPY packages/shared ./packages/shared
|
|
||||||
COPY services/discord-gateway ./services/discord-gateway
|
COPY services/discord-gateway ./services/discord-gateway
|
||||||
COPY services/discord-gateway/drizzle ./drizzle
|
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 \
|
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||||
pnpm --filter './packages/shared' run build \
|
cd services/discord-gateway && pnpm run build \
|
||||||
&& pnpm --filter './services/discord-gateway' run build \
|
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& 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) ----
|
# ---- Stage 2: Runtime (minimal) ----
|
||||||
FROM node:22-slim
|
FROM node:22-slim
|
||||||
|
|
||||||
@@ -57,11 +40,10 @@ RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends \
|
|||||||
ffmpeg ca-certificates \
|
ffmpeg ca-certificates \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy production-only artifacts from deploy
|
# Copy built artifacts
|
||||||
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 --from=builder /app/services/discord-gateway/dist ./services/discord-gateway/dist
|
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
|
COPY --from=builder /app/drizzle ./drizzle
|
||||||
|
|
||||||
# Create recordings dir and set ownership
|
# 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/*
|
python3 make g++ && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy dependency manifests first for layer caching
|
# Copy dependency manifests first for layer caching
|
||||||
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
|
COPY services/frontend/package.json services/frontend/pnpm-lock.yaml* ./services/frontend/
|
||||||
COPY packages/shared/package.json ./packages/shared/package.json
|
|
||||||
COPY services/frontend/package.json ./services/frontend/package.json
|
|
||||||
COPY services/frontend/tsconfig.json ./services/frontend/tsconfig.json
|
COPY services/frontend/tsconfig.json ./services/frontend/tsconfig.json
|
||||||
|
|
||||||
# Copy patches (pnpm patchedDependencies)
|
# Install frontend dependencies (standalone, no shared workspace dep)
|
||||||
COPY patches/ ./patches/
|
|
||||||
|
|
||||||
# Install dependencies (frontend + shared)
|
|
||||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
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 source code
|
||||||
COPY packages/shared/ ./packages/shared/
|
|
||||||
COPY services/frontend/ ./services/frontend/
|
COPY services/frontend/ ./services/frontend/
|
||||||
|
|
||||||
# Pass API/WS URLs as build args
|
# 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_API_URL=${VITE_BE_API_URL}
|
||||||
ENV VITE_BE_WS_URL=${VITE_BE_WS_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 \
|
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
||||||
pnpm --filter './packages/shared' run build
|
cd services/frontend && pnpm run build
|
||||||
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
|
|
||||||
pnpm --filter frontend run build
|
|
||||||
|
|
||||||
# ---- Stage 2: Nginx ----
|
# ---- Stage 2: Nginx ----
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|||||||
+11
-18
@@ -1,31 +1,24 @@
|
|||||||
{
|
{
|
||||||
"name": "discord-voice-recorder",
|
"name": "bete-monorepo",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Discord bot that joins a voice channel and records audio",
|
"private": true,
|
||||||
"type": "module",
|
"description": "Bete Discord Moderation Services — standalone services in one repo",
|
||||||
"packageManager": "pnpm@11.1.3",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:backend": "pnpm --filter './services/backend' run dev",
|
"dev:backend": "pnpm --prefix services/backend dev",
|
||||||
"dev:discord-gateway": "pnpm --filter './services/discord-gateway' run dev",
|
"dev:discord-gateway": "pnpm --prefix services/discord-gateway dev",
|
||||||
"dev:web": "pnpm --filter './services/frontend' run dev",
|
"dev:web": "pnpm --prefix services/frontend dev",
|
||||||
"build:web": "pnpm --filter './services/frontend' run build",
|
"build:web": "pnpm --prefix services/frontend build",
|
||||||
"typecheck:web": "pnpm --filter './services/frontend' run build",
|
"build:backend": "pnpm --prefix services/backend build",
|
||||||
"build:backend": "pnpm --filter './services/backend' run build",
|
"build:discord-gateway": "pnpm --prefix services/discord-gateway build",
|
||||||
"build:discord-gateway": "pnpm --filter './services/discord-gateway' run build",
|
"typecheck": "pnpm --prefix services/backend typecheck && pnpm --prefix services/discord-gateway typecheck",
|
||||||
"typecheck": "pnpm -r run typecheck",
|
|
||||||
"lint": "biome check --diagnostic-level=error .",
|
"lint": "biome check --diagnostic-level=error .",
|
||||||
"format": "biome format --write .",
|
"format": "biome format --write .",
|
||||||
"test": "pnpm -r run test",
|
"test": "pnpm --prefix services/backend test && pnpm --prefix services/discord-gateway test",
|
||||||
"db:generate": "drizzle-kit generate",
|
|
||||||
"db:migrate": "drizzle-kit migrate",
|
|
||||||
"db:studio": "drizzle-kit studio",
|
|
||||||
"db:truncate": "psql \"$DATABASE_URL\" -f scripts/truncate-all.sql",
|
"db:truncate": "psql \"$DATABASE_URL\" -f scripts/truncate-all.sql",
|
||||||
"install:yt-dlp": "sh scripts/install-yt-dlp.sh"
|
"install:yt-dlp": "sh scripts/install-yt-dlp.sh"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^2.5.5",
|
"@biomejs/biome": "^2.5.5",
|
||||||
"drizzle-kit": "^0.31.10",
|
|
||||||
"tsx": "^4.22.2",
|
|
||||||
"typescript": "^5.9.3"
|
"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"
|
"test": "vitest run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bete/shared": "workspace:*",
|
|
||||||
"@discordjs/voice": "^0.19.2",
|
"@discordjs/voice": "^0.19.2",
|
||||||
"axios": "^1.16.1",
|
"axios": "^1.16.1",
|
||||||
"dotenv": "^17.4.2",
|
"dotenv": "^17.4.2",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import express, {
|
import express, {
|
||||||
type Express,
|
type Express,
|
||||||
type NextFunction,
|
type NextFunction,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createServer, type Server } from "node:http";
|
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 { config } from "../shared/config/index.js";
|
||||||
import { initializeDatabase } from "../shared/database/index.js";
|
import { initializeDatabase } from "../shared/database/index.js";
|
||||||
import { startRedisBridge } from "../ws/redis-bridge.js";
|
import { startRedisBridge } from "../ws/redis-bridge.js";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Server } from "node:http";
|
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 { startHttpServer } from "./http/server.js";
|
||||||
import { closeDatabase } from "./shared/database/index.js";
|
import { closeDatabase } from "./shared/database/index.js";
|
||||||
import { stopCommandBridge } from "./shared/redis/index.js";
|
import { stopCommandBridge } from "./shared/redis/index.js";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { pgMessagesTable } from "@bete/shared";
|
import { pgMessagesTable } from "../../shared/index.js";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "../../shared/logger/index.js";
|
||||||
import { and, desc, eq, ilike, type SQL } from "drizzle-orm";
|
import { and, desc, eq, ilike, type SQL } from "drizzle-orm";
|
||||||
import { getDatabase } from "../../shared/database/index.js";
|
import { getDatabase } from "../../shared/database/index.js";
|
||||||
import {
|
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 type { Request, Response, Router } from "express";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
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 { config } from "../../shared/config/index.js";
|
||||||
import type { AnalysisSearchQuery } from "./analysis.repository.js";
|
import type { AnalysisSearchQuery } from "./analysis.repository.js";
|
||||||
import { analysisRepository } 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 type { Request, Response } from "express";
|
||||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||||
import { chatbotService } from "./chatbot.service.js";
|
import { chatbotService } from "./chatbot.service.js";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { pgChatbotMessagesTable, pgMessagesTable } from "@bete/shared";
|
import { pgChatbotMessagesTable, pgMessagesTable } from "../../shared/index.js";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "../../shared/logger/index.js";
|
||||||
import { and, desc, eq, type SQL, sql } from "drizzle-orm";
|
import { and, desc, eq, type SQL, sql } from "drizzle-orm";
|
||||||
import { getDatabase } from "../../shared/database/index.js";
|
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 { config } from "../../shared/config/index.js";
|
||||||
import type {
|
import type {
|
||||||
ChatbotContext,
|
ChatbotContext,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
pgUserProfilesTable,
|
pgUserProfilesTable,
|
||||||
pgUserReputationsTable,
|
pgUserReputationsTable,
|
||||||
pgVoiceRecordingsTable,
|
pgVoiceRecordingsTable,
|
||||||
} from "@bete/shared";
|
} from "../../shared/index.js";
|
||||||
import type { SQL } from "drizzle-orm";
|
import type { SQL } from "drizzle-orm";
|
||||||
import { sql } from "drizzle-orm";
|
import { sql } from "drizzle-orm";
|
||||||
import { getDatabase } from "../../shared/database/index.js";
|
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 type { Request, Response, Router } from "express";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
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";
|
import { dashboardRepository } from "./dashboard.repository.js";
|
||||||
|
|
||||||
const logger = createChildLogger("dashboard.service");
|
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 { sql } from "drizzle-orm";
|
||||||
import { getDatabase } from "../../shared/database/index.js";
|
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 type { Request, Response, Router } from "express";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { asyncHandler, validateBody } from "../../shared/middlewares/index.js";
|
import { asyncHandler, validateBody } from "../../shared/middlewares/index.js";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
COMMAND_MEDIA_STOP,
|
COMMAND_MEDIA_STOP,
|
||||||
COMMAND_MEDIA_VOLUME,
|
COMMAND_MEDIA_VOLUME,
|
||||||
MEDIA_STATUS_KEY,
|
MEDIA_STATUS_KEY,
|
||||||
} from "@bete/shared";
|
} from "../../shared/index.js";
|
||||||
import {
|
import {
|
||||||
createChildLogger,
|
createChildLogger,
|
||||||
tryCommandThenFallback,
|
tryCommandThenFallback,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import type { Request, Response } from "express";
|
import type { Request, Response } from "express";
|
||||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||||
import { messageQuerySchema } from "./messages.schema.js";
|
import { messageQuerySchema } from "./messages.schema.js";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { PageResult } from "@bete/shared";
|
import type { PageResult } from "../../shared/index.js";
|
||||||
import { pgAttachmentsTable, pgMessagesTable } from "@bete/shared";
|
import { pgAttachmentsTable, pgMessagesTable } from "../../shared/index.js";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "../../shared/logger/index.js";
|
||||||
import {
|
import {
|
||||||
and,
|
and,
|
||||||
desc,
|
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 type { Request, Response, Router } from "express";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { asyncHandler, validateBody } from "../../shared/middlewares/index.js";
|
import { asyncHandler, validateBody } from "../../shared/middlewares/index.js";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { NotFoundError, ValidationError } from "@bete/shared/errors";
|
import { NotFoundError, ValidationError } from "@/shared/errors/index";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { messagesRepository } from "./messages.repository.js";
|
import { messagesRepository } from "./messages.repository.js";
|
||||||
import type { MessageQuery } from "./messages.schema.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 type { Request, Response, Router } from "express";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { pgVoiceRecordingsTable } from "@bete/shared";
|
import { pgVoiceRecordingsTable } from "../../shared/index.js";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "../../shared/logger/index.js";
|
||||||
import { and, desc, eq, lt, type SQL } from "drizzle-orm";
|
import { and, desc, eq, lt, type SQL } from "drizzle-orm";
|
||||||
import { getDatabase } from "../../shared/database/index.js";
|
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 type { Request, Response, Router } from "express";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
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 { sql } from "drizzle-orm";
|
||||||
import { getDatabase } from "../../shared/database/index.js";
|
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 type { Request, Response } from "express";
|
||||||
import { asyncHandler } from "../../shared/middlewares/index.js";
|
import { asyncHandler } from "../../shared/middlewares/index.js";
|
||||||
import { publishCommandNoReply } from "../../shared/redis/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 type { Request, Response, Router } from "express";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { asyncHandler, validateBody } from "../../shared/middlewares/index.js";
|
import { asyncHandler, validateBody } from "../../shared/middlewares/index.js";
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
type CommandReply,
|
type CommandReply,
|
||||||
pgMessagesTable,
|
pgMessagesTable,
|
||||||
VOICE_STATUS_KEY,
|
VOICE_STATUS_KEY,
|
||||||
} from "@bete/shared";
|
} from "../../shared/index.js";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
createChildLogger,
|
createChildLogger,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { CommandReply } from "@bete/shared";
|
import type { CommandReply } from "./index.js";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "./logger/index.js";
|
||||||
|
|
||||||
export { createChildLogger };
|
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,
|
getDatabase as sharedGetDb,
|
||||||
getPool as sharedGetPool,
|
getPool as sharedGetPool,
|
||||||
initializeDatabase as sharedInit,
|
initializeDatabase as sharedInit,
|
||||||
} from "@bete/shared/database/init";
|
} from "@/shared/database/init";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { config } from "../config/index.js";
|
import { config } from "../config/index.js";
|
||||||
|
|
||||||
const logger = createChildLogger("database");
|
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 { drizzle } from "drizzle-orm/node-postgres";
|
||||||
import type { Pool, PoolClient } from "pg";
|
import type { Pool, PoolClient } from "pg";
|
||||||
import { closePool, createPoolFromConfig } from "./pool.js";
|
import { closePool, createPoolFromConfig } from "./pool.js";
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { AppError, ValidationError } from "@bete/shared/errors";
|
import { AppError, ValidationError } from "@/shared/errors/index";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import type { NextFunction, Request, Response } from "express";
|
import type { NextFunction, Request, Response } from "express";
|
||||||
import type { ZodSchema } from "zod";
|
import type { ZodSchema } from "zod";
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import {
|
|||||||
BACKEND_COMMAND_REPLY_PREFIX,
|
BACKEND_COMMAND_REPLY_PREFIX,
|
||||||
type CommandMessage,
|
type CommandMessage,
|
||||||
type CommandReply,
|
type CommandReply,
|
||||||
} from "@bete/shared";
|
} from "../index.js";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "../logger/index.js";
|
||||||
import Redis from "ioredis";
|
import Redis from "ioredis";
|
||||||
import { config } from "../config/index.js";
|
import { config } from "../config/index.js";
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
* broadcastEvent("message_created", messageData);
|
* broadcastEvent("message_created", messageData);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
|
|
||||||
const logger = createChildLogger("broadcast");
|
const logger = createChildLogger("broadcast");
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DISCORD_CHANNEL_TO_WS_EVENT, DISCORD_VOICE_PCM } from "@bete/shared";
|
import { DISCORD_CHANNEL_TO_WS_EVENT, DISCORD_VOICE_PCM } from "../shared/index.js";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "../shared/logger/index.js";
|
||||||
import Redis from "ioredis";
|
import Redis from "ioredis";
|
||||||
import { config } from "../shared/config/index.js";
|
import { config } from "../shared/config/index.js";
|
||||||
import { broadcastBinary, broadcastEvent } from "./broadcast.js";
|
import { broadcastBinary, broadcastEvent } from "./broadcast.js";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Server } from "node:http";
|
import type { Server } from "node:http";
|
||||||
import { BACKEND_COMMAND, BACKEND_VOICE_TRANSMIT } from "@bete/shared";
|
import { BACKEND_COMMAND, BACKEND_VOICE_TRANSMIT } from "../shared/index.js";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "../shared/logger/index.js";
|
||||||
import { WebSocket, WebSocketServer } from "ws";
|
import { WebSocket, WebSocketServer } from "ws";
|
||||||
import { config } from "../shared/config/index.js";
|
import { config } from "../shared/config/index.js";
|
||||||
import { setBroadcastFunctions } from "./broadcast.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"
|
"test": "vitest run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bete/shared": "workspace:*",
|
|
||||||
"@discordjs/opus": "^0.10.0",
|
"@discordjs/opus": "^0.10.0",
|
||||||
"@discordjs/voice": "^0.19.2",
|
"@discordjs/voice": "^0.19.2",
|
||||||
"@snazzah/davey": "^0.1.11",
|
"@snazzah/davey": "^0.1.11",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ConfigError, DatabaseError } from "@bete/shared/errors";
|
import { ConfigError, DatabaseError } from "@/shared/errors/index";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { Client } from "discord.js-selfbot-v13";
|
import { Client } from "discord.js-selfbot-v13";
|
||||||
import { inArray, lt } from "drizzle-orm";
|
import { inArray, lt } from "drizzle-orm";
|
||||||
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
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 { inArray, lt } from "drizzle-orm";
|
||||||
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
||||||
import { config } from "../shared/config/config.js";
|
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 { Client } from "discord.js-selfbot-v13";
|
||||||
import type { CommandHandler } from "../modules/command-handler/commandHandler.js";
|
import type { CommandHandler } from "../modules/command-handler/commandHandler.js";
|
||||||
import type { EventBroadcaster } from "../modules/event-broadcaster/index.js";
|
import type { EventBroadcaster } from "../modules/event-broadcaster/index.js";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import "libsodium-wrappers";
|
import "libsodium-wrappers";
|
||||||
import "@snazzah/davey";
|
import "@snazzah/davey";
|
||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { initializeDiscordGateway } from "./app/bootstrap.js";
|
import { initializeDiscordGateway } from "./app/bootstrap.js";
|
||||||
|
|
||||||
const logger = createChildLogger("discord-gateway");
|
const logger = createChildLogger("discord-gateway");
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
* simpler, unified worker that combines both layers.
|
* 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 { config } from "../../shared/config/config.js";
|
||||||
import { initializeDatabase } from "../../shared/database/drizzle.js";
|
import { initializeDatabase } from "../../shared/database/drizzle.js";
|
||||||
import { messageStore } from "../message-capture/messageStore.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 type { Client } from "discord.js-selfbot-v13";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import type { EventBroadcaster } from "../event-broadcaster/index.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 { config } from "../../shared/config/config.js";
|
||||||
import { initializeDatabase } from "../../shared/database/drizzle.js";
|
import { initializeDatabase } from "../../shared/database/drizzle.js";
|
||||||
import { extractMessageMediaEvidence } from "../message-capture/messageMetadata.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 { config } from "../../shared/config/config.js";
|
||||||
import type {
|
import type {
|
||||||
AnalysisResult,
|
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 type { Guild } from "discord.js-selfbot-v13";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import type { MessageRecord } from "../message-capture/types.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 type { Client, PermissionString } from "discord.js-selfbot-v13";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import { messageStore } from "../message-capture/messageStore.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 type { Client } from "discord.js-selfbot-v13";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import type { MessageRecord } from "../message-capture/types.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 { config } from "../../shared/config/config.js";
|
||||||
import { isAgeRestrictedMetadata } from "../message-capture/messageMetadata.js";
|
import { isAgeRestrictedMetadata } from "../message-capture/messageMetadata.js";
|
||||||
import { messageStore } from "../message-capture/messageStore.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 { config } from "../../shared/config/config.js";
|
||||||
import { messageStore } from "../message-capture/messageStore.js";
|
import { messageStore } from "../message-capture/messageStore.js";
|
||||||
import type { MessageRecord } from "../message-capture/types.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 { eq } from "drizzle-orm";
|
||||||
import { getDatabase } from "../../shared/database/drizzle.js";
|
import { getDatabase } from "../../shared/database/drizzle.js";
|
||||||
import {
|
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 { encoding_for_model as encodingForModel } from "tiktoken";
|
||||||
import { formatMediaEvidenceForPrompt } from "../message-capture/messageMetadata.js";
|
import { formatMediaEvidenceForPrompt } from "../message-capture/messageMetadata.js";
|
||||||
import type { MessageRecord } from "../message-capture/types.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 { LRUCache } from "lru-cache";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import { LAST_ERROR } from "./moderationState.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 { and, desc, eq, sql } from "drizzle-orm";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import { getDatabase } from "../../shared/database/drizzle.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 { LRUCache } from "lru-cache";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import { messageStore } from "../message-capture/messageStore.js";
|
import { messageStore } from "../message-capture/messageStore.js";
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
*
|
*
|
||||||
* Both sides now import from this module instead.
|
* Both sides now import from this module instead.
|
||||||
*/
|
*/
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { delay, retryWithBackoff } from "@bete/shared/utils";
|
import { delay, retryWithBackoff } from "@/shared/utils/index";
|
||||||
import type { ChatCompletion } from "openai/resources/chat/completions";
|
import type { ChatCompletion } from "openai/resources/chat/completions";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import type { AnalysisResult } from "../message-capture/types.js";
|
import type { AnalysisResult } from "../message-capture/types.js";
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
* defaults are maintained in one place.
|
* defaults are maintained in one place.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { retryWithBackoff } from "@bete/shared/utils";
|
import { retryWithBackoff } from "@/shared/utils/index";
|
||||||
import OpenAI from "openai";
|
import OpenAI from "openai";
|
||||||
import pLimit from "p-limit";
|
import pLimit from "p-limit";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* analysis, and calls the LLM for a batched moderation response. Extracted from
|
* analysis, and calls the LLM for a batched moderation response. Extracted from
|
||||||
* moderationOrchestrator.ts.
|
* moderationOrchestrator.ts.
|
||||||
*/
|
*/
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import type {
|
import type {
|
||||||
AnalysisResult,
|
AnalysisResult,
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { mkdtemp, readFile, rm, unlink, writeFile } from "node:fs/promises";
|
|||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { promisify } from "node:util";
|
import { promisify } from "node:util";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { createAbortControllerWithTimeout } from "@bete/shared/utils";
|
import { createAbortControllerWithTimeout } from "@/shared/utils/index";
|
||||||
import { resizeImageForVision } from "../attachment-upload/imageResizer.js";
|
import { resizeImageForVision } from "../attachment-upload/imageResizer.js";
|
||||||
import type { MessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
import type { MessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
||||||
import type { AttachmentRecord } from "../message-capture/types.js";
|
import type { AttachmentRecord } from "../message-capture/types.js";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Orchestrates LLM-based moderation analysis — manages batch splitting,
|
* Orchestrates LLM-based moderation analysis — manages batch splitting,
|
||||||
* parallel text+media analysis, LLM calls with retry, and cache handling.
|
* 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 { config } from "../../shared/config/config.js";
|
||||||
import { extractMessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
import { extractMessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
||||||
import type {
|
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 { z } from "zod";
|
||||||
import type { AnalysisResult } from "../message-capture/types.js";
|
import type { AnalysisResult } from "../message-capture/types.js";
|
||||||
import type {
|
import type {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
const log = createChildLogger("moderationSchemas");
|
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 type { Client } from "discord.js-selfbot-v13";
|
||||||
import { LRUCache } from "lru-cache";
|
import { LRUCache } from "lru-cache";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
* Enables full audit trail and debugging of moderation decisions.
|
* 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";
|
import type { AnalysisResult } from "../message-capture/types.js";
|
||||||
|
|
||||||
const logger = createChildLogger("response-logger");
|
const logger = createChildLogger("response-logger");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { createAbortControllerWithTimeout } from "@bete/shared/utils";
|
import { createAbortControllerWithTimeout } from "@/shared/utils/index";
|
||||||
import Redis from "ioredis";
|
import Redis from "ioredis";
|
||||||
|
|
||||||
const log = createChildLogger("searxng-search");
|
const log = createChildLogger("searxng-search");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Step 2: Real analysis text (only if not clean).
|
* Step 2: Real analysis text (only if not clean).
|
||||||
* Extracted from moderationOrchestrator.ts.
|
* Extracted from moderationOrchestrator.ts.
|
||||||
*/
|
*/
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import type {
|
import type {
|
||||||
AnalysisResult,
|
AnalysisResult,
|
||||||
MessageRecord,
|
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 { config } from "../../shared/config/config.js";
|
||||||
import { executeAll, executeGet } from "../../shared/database/drizzle.js";
|
import { executeAll, executeGet } from "../../shared/database/drizzle.js";
|
||||||
import { uploadToTele } from "../../shared/uploader.js";
|
import { uploadToTele } from "../../shared/uploader.js";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* searches, deduplicates short messages, splits into sub-batches, and calls
|
* searches, deduplicates short messages, splits into sub-batches, and calls
|
||||||
* the LLM for analysis. Extracted from moderationOrchestrator.ts.
|
* 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 { config } from "../../shared/config/config.js";
|
||||||
import type {
|
import type {
|
||||||
AnalysisResult,
|
AnalysisResult,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createHash } from "node:crypto";
|
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";
|
import { executeAll, executeGet } from "../../shared/database/drizzle.js";
|
||||||
|
|
||||||
const logger = createChildLogger("text-cache-store");
|
const logger = createChildLogger("text-cache-store");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { resolve } from "node:dns/promises";
|
import { resolve } from "node:dns/promises";
|
||||||
import { isIP } from "node:net";
|
import { isIP } from "node:net";
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { createAbortControllerWithTimeout } from "@bete/shared/utils";
|
import { createAbortControllerWithTimeout } from "@/shared/utils/index";
|
||||||
|
|
||||||
const _log = createChildLogger("urlFetcher");
|
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 { and, desc, eq, sql } from "drizzle-orm";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import { getDatabase } from "../../shared/database/drizzle.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 { eq } from "drizzle-orm";
|
||||||
import { getDatabase } from "../../shared/database/drizzle.js";
|
import { getDatabase } from "../../shared/database/drizzle.js";
|
||||||
import {
|
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 { and, desc, eq } from "drizzle-orm";
|
||||||
import { getDatabase } from "../../shared/database/drizzle.js";
|
import { getDatabase } from "../../shared/database/drizzle.js";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
* moderation pipeline, runs single-image vision LLM analysis with
|
* moderation pipeline, runs single-image vision LLM analysis with
|
||||||
* multi-layer caching, and detects whether a message has media content.
|
* multi-layer caching, and detects whether a message has media content.
|
||||||
*/
|
*/
|
||||||
import { createChildLogger } from "@bete/shared/logger";
|
import { createChildLogger } from "@/shared/logger/index";
|
||||||
import { delay } from "@bete/shared/utils";
|
import { delay } from "@/shared/utils/index";
|
||||||
import { config } from "../../shared/config/config.js";
|
import { config } from "../../shared/config/config.js";
|
||||||
import { extractMessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
import { extractMessageMediaEvidence } from "../message-capture/messageMetadata.js";
|
||||||
import type {
|
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 { config } from "../../shared/config/config.js";
|
||||||
import { uploadToTele } from "../../shared/uploader.js";
|
import { uploadToTele } from "../../shared/uploader.js";
|
||||||
import { messageStore } from "../message-capture/messageStore.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";
|
import sharp from "sharp";
|
||||||
|
|
||||||
const log = createChildLogger("imageResizer");
|
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