chore: make docker
This commit is contained in:
11
.dockerignore
Normal file
11
.dockerignore
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.env
|
||||||
|
.envrc
|
||||||
|
node_modules
|
||||||
|
data
|
||||||
|
build
|
||||||
|
.DS_Store
|
||||||
|
README.md
|
||||||
|
flake.nix
|
||||||
|
flake.lock
|
||||||
@@ -8,7 +8,7 @@ OPENAI_API_KEY=""
|
|||||||
OPENROUTER_API_KEY=""
|
OPENROUTER_API_KEY=""
|
||||||
AI_CLASSIFICATION_MODEL="google/gemma-3-12b-it:free"
|
AI_CLASSIFICATION_MODEL="google/gemma-3-12b-it:free"
|
||||||
AI_CLASSIFICATION_FALLBACK_MODELS="meta-llama/llama-3.3-70b-instruct:free,mistralai/mistral-small-3.1-24b-instruct:free"
|
AI_CLASSIFICATION_FALLBACK_MODELS="meta-llama/llama-3.3-70b-instruct:free,mistralai/mistral-small-3.1-24b-instruct:free"
|
||||||
REPLICATE_API_TOKEN=""
|
REPLICATE_API_KEY=""
|
||||||
ELEVENLABS_API_KEY=""
|
ELEVENLABS_API_KEY=""
|
||||||
ELEVENLABS_VOICE_ID=""
|
ELEVENLABS_VOICE_ID=""
|
||||||
ELEVENLABS_MODEL="eleven_multilingual_v2"
|
ELEVENLABS_MODEL="eleven_multilingual_v2"
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ RUN bun install --frozen-lockfile
|
|||||||
COPY src ./src
|
COPY src ./src
|
||||||
COPY tsconfig.json drizzle.config.ts ./
|
COPY tsconfig.json drizzle.config.ts ./
|
||||||
|
|
||||||
|
RUN bun run css:build
|
||||||
|
|
||||||
# Production stage
|
# Production stage
|
||||||
FROM oven/bun:1-slim
|
FROM oven/bun:1-slim
|
||||||
|
|
||||||
@@ -25,7 +27,7 @@ WORKDIR /app
|
|||||||
|
|
||||||
# Install runtime dependencies
|
# Install runtime dependencies
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends ffmpeg \
|
&& apt-get install -y --no-install-recommends ffmpeg ca-certificates \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy from builder
|
# Copy from builder
|
||||||
@@ -33,14 +35,18 @@ COPY --from=builder /app/node_modules ./node_modules
|
|||||||
COPY --from=builder /app/src ./src
|
COPY --from=builder /app/src ./src
|
||||||
COPY --from=builder /app/package.json ./
|
COPY --from=builder /app/package.json ./
|
||||||
COPY --from=builder /app/tsconfig.json ./
|
COPY --from=builder /app/tsconfig.json ./
|
||||||
|
COPY --from=builder /app/drizzle.config.ts ./
|
||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV LOG_LEVEL=info
|
ENV LOG_LEVEL=info
|
||||||
ENV DATABASE_PATH=/data/db.sqlite3
|
ENV DATABASE_PATH=/data/db.sqlite3
|
||||||
|
ENV WEB_PORT=3000
|
||||||
|
|
||||||
# Persist runtime data (SQLite)
|
# Persist runtime data (SQLite)
|
||||||
VOLUME ["/data"]
|
VOLUME ["/data"]
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
# Run the bot
|
# Run the bot
|
||||||
CMD ["bun", "run", "src/index.ts"]
|
CMD ["bun", "run", "src/index.ts"]
|
||||||
|
|||||||
50
README.md
50
README.md
@@ -72,6 +72,56 @@ docker run -d \
|
|||||||
your-image:latest
|
your-image:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
Build the image:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t ghcr.io/your-org/joel-bot:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
Run it locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name joel-bot \
|
||||||
|
-p 3000:3000 \
|
||||||
|
-v joel_data:/data \
|
||||||
|
--env-file .env \
|
||||||
|
ghcr.io/your-org/joel-bot:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
The container now starts in production mode and does not enable the CSS file watcher.
|
||||||
|
|
||||||
|
## k3s
|
||||||
|
|
||||||
|
The repo includes starter manifests in [`k8s/deployment.yaml`](/Users/eric/Projects/joel-discord/k8s/deployment.yaml), [`k8s/secret.example.yaml`](/Users/eric/Projects/joel-discord/k8s/secret.example.yaml), and [`k8s/ingress.example.yaml`](/Users/eric/Projects/joel-discord/k8s/ingress.example.yaml).
|
||||||
|
|
||||||
|
Typical flow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build and push the image
|
||||||
|
docker build -t ghcr.io/your-org/joel-bot:latest .
|
||||||
|
docker push ghcr.io/your-org/joel-bot:latest
|
||||||
|
|
||||||
|
# Create your secret manifest from the example and fill in real values
|
||||||
|
cp k8s/secret.example.yaml k8s/secret.yaml
|
||||||
|
|
||||||
|
# Apply namespace, PVC, deployment, and service
|
||||||
|
kubectl apply -f k8s/deployment.yaml
|
||||||
|
kubectl apply -f k8s/secret.yaml
|
||||||
|
|
||||||
|
# Optional if you want the web UI exposed through Traefik
|
||||||
|
kubectl apply -f k8s/ingress.example.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- Update the image in `k8s/deployment.yaml` to your registry path.
|
||||||
|
- Set `WEB_BASE_URL` in the secret to the public HTTPS URL you expose through ingress.
|
||||||
|
- The deployment mounts `/data` on a PVC and stores SQLite at `/data/db.sqlite3`.
|
||||||
|
- k3s usually provisions the PVC automatically via the default `local-path` storage class.
|
||||||
|
|
||||||
## Scripts
|
## Scripts
|
||||||
|
|
||||||
| Script | Description |
|
| Script | Description |
|
||||||
|
|||||||
148
flake.lock
generated
148
flake.lock
generated
@@ -16,6 +16,22 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-compat_2": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767039857,
|
||||||
|
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"git-hooks": {
|
"git-hooks": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
@@ -36,6 +52,26 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"git-hooks_2": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat_2",
|
||||||
|
"gitignore": "gitignore_2",
|
||||||
|
"nixpkgs": "nixpkgs_3"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1772024342,
|
||||||
|
"narHash": "sha256-+eXlIc4/7dE6EcPs9a2DaSY3fTA9AE526hGqkNID3Wg=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"rev": "6e34e97ed9788b17796ee43ccdbaf871a5c2b476",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"gitignore": {
|
"gitignore": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -57,6 +93,28 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"gitignore_2": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"repo-lib",
|
||||||
|
"git-hooks",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1709087332,
|
||||||
|
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1764947035,
|
"lastModified": 1764947035,
|
||||||
@@ -89,10 +147,98 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1770073757,
|
||||||
|
"narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "47472570b1e607482890801aeaf29bfb749884f6",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_4": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1772542754,
|
||||||
|
"narHash": "sha256-WGV2hy+VIeQsYXpsLjdr4GvHv5eECMISX1zKLTedhdg=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "8c809a146a140c5c8806f13399592dbcb1bb5dc4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_5": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1770107345,
|
||||||
|
"narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "4533d9293756b63904b7238acb84ac8fe4c8c2c4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repo-lib": {
|
||||||
|
"inputs": {
|
||||||
|
"git-hooks": "git-hooks_2",
|
||||||
|
"nixpkgs": "nixpkgs_4",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1772866275,
|
||||||
|
"narHash": "sha256-lsJrFIbq6OO5wUC648VnvOmJm3qgJrlEugbdjeZsP34=",
|
||||||
|
"ref": "refs/tags/v3.0.0",
|
||||||
|
"rev": "96d2d190466dddcb9e652c38b70152f09b9fcb05",
|
||||||
|
"revCount": 50,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.dgren.dev/eric/nix-flake-lib"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"ref": "refs/tags/v3.0.0",
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.dgren.dev/eric/nix-flake-lib"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"git-hooks": "git-hooks",
|
"git-hooks": "git-hooks",
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2",
|
||||||
|
"repo-lib": "repo-lib"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_5"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1770228511,
|
||||||
|
"narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "337a4fe074be1042a35086f15481d763b8ddc0e7",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
git-hooks.url = "github:cachix/git-hooks.nix";
|
git-hooks.url = "github:cachix/git-hooks.nix";
|
||||||
|
repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.0.0";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
|
|||||||
91
k8s/deployment.yaml
Normal file
91
k8s/deployment.yaml
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: joel-bot
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: joel-bot-data
|
||||||
|
namespace: joel-bot
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: joel-bot
|
||||||
|
namespace: joel-bot
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
revisionHistoryLimit: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: joel-bot
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: joel-bot
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: joel-bot
|
||||||
|
image: ghcr.io/your-org/joel-bot:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
- name: NODE_ENV
|
||||||
|
value: "production"
|
||||||
|
- name: LOG_LEVEL
|
||||||
|
value: "info"
|
||||||
|
- name: DATABASE_PATH
|
||||||
|
value: /data/db.sqlite3
|
||||||
|
- name: WEB_PORT
|
||||||
|
value: "3000"
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: joel-bot-env
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 3000
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 1Gi
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: joel-bot-data
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: joel-bot
|
||||||
|
namespace: joel-bot
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: joel-bot
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 3000
|
||||||
|
targetPort: http
|
||||||
23
k8s/ingress.example.yaml
Normal file
23
k8s/ingress.example.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: joel-bot
|
||||||
|
namespace: joel-bot
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: traefik
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: joel.example.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: joel-bot
|
||||||
|
port:
|
||||||
|
number: 3000
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- joel.example.com
|
||||||
|
secretName: joel-bot-tls
|
||||||
23
k8s/secret.example.yaml
Normal file
23
k8s/secret.example.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: joel-bot-env
|
||||||
|
namespace: joel-bot
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
DISCORD_TOKEN: ""
|
||||||
|
DISCORD_CLIENT_ID: ""
|
||||||
|
DISCORD_CLIENT_SECRET: ""
|
||||||
|
OPENROUTER_API_KEY: ""
|
||||||
|
OPENAI_API_KEY: ""
|
||||||
|
HF_TOKEN: ""
|
||||||
|
REPLICATE_API_KEY: ""
|
||||||
|
FAL_KEY: ""
|
||||||
|
KLIPY_API_KEY: ""
|
||||||
|
ELEVENLABS_API_KEY: ""
|
||||||
|
ELEVENLABS_VOICE_ID: ""
|
||||||
|
ELEVENLABS_MODEL: "eleven_multilingual_v2"
|
||||||
|
AI_CLASSIFICATION_MODEL: "google/gemma-3-12b-it:free"
|
||||||
|
AI_CLASSIFICATION_FALLBACK_MODELS: "meta-llama/llama-3.3-70b-instruct:free,mistralai/mistral-small-3.1-24b-instruct:free"
|
||||||
|
WEB_BASE_URL: "https://joel.example.com"
|
||||||
|
SESSION_SECRET: "replace-with-a-long-random-secret"
|
||||||
@@ -66,6 +66,17 @@ function getEnvOrDefault(key: string, defaultValue: string): string {
|
|||||||
return Bun.env[key] ?? defaultValue;
|
return Bun.env[key] ?? defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFirstEnvOrDefault(keys: string[], defaultValue: string): string {
|
||||||
|
for (const key of keys) {
|
||||||
|
const value = Bun.env[key];
|
||||||
|
if (value !== undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
function getBooleanEnvOrDefault(key: string, defaultValue: boolean): boolean {
|
function getBooleanEnvOrDefault(key: string, defaultValue: boolean): boolean {
|
||||||
const raw = Bun.env[key];
|
const raw = Bun.env[key];
|
||||||
if (raw === undefined) {
|
if (raw === undefined) {
|
||||||
@@ -112,7 +123,7 @@ export const config: BotConfig = {
|
|||||||
temperature: parseFloat(getEnvOrDefault("AI_TEMPERATURE", "1.2")),
|
temperature: parseFloat(getEnvOrDefault("AI_TEMPERATURE", "1.2")),
|
||||||
},
|
},
|
||||||
replicate: {
|
replicate: {
|
||||||
apiKey: getEnvOrDefault("REPLICATE_API_KEY", ""),
|
apiKey: getFirstEnvOrDefault(["REPLICATE_API_KEY", "REPLICATE_API_TOKEN"], ""),
|
||||||
},
|
},
|
||||||
fal: {
|
fal: {
|
||||||
apiKey: getEnvOrDefault("FAL_KEY", ""),
|
apiKey: getEnvOrDefault("FAL_KEY", ""),
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import type { FSWatcher } from "fs";
|
|||||||
|
|
||||||
const logger = createLogger("Main");
|
const logger = createLogger("Main");
|
||||||
let webCssWatcher: FSWatcher | null = null;
|
let webCssWatcher: FSWatcher | null = null;
|
||||||
|
const isProduction = Bun.env.NODE_ENV === "production";
|
||||||
|
|
||||||
// Create the Discord client with required intents
|
// Create the Discord client with required intents
|
||||||
const client = new BotClient({
|
const client = new BotClient({
|
||||||
@@ -53,7 +54,9 @@ async function main(): Promise<void> {
|
|||||||
|
|
||||||
// Start web server after bot is logged in
|
// Start web server after bot is logged in
|
||||||
await buildWebCss();
|
await buildWebCss();
|
||||||
webCssWatcher = startWebCssWatcher();
|
if (!isProduction) {
|
||||||
|
webCssWatcher = startWebCssWatcher();
|
||||||
|
}
|
||||||
await startWebServer(client);
|
await startWebServer(client);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("Failed to start bot", error);
|
logger.error("Failed to start bot", error);
|
||||||
|
|||||||
Reference in New Issue
Block a user