valheim-oz-dsm 1.8.0 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,20 +5,22 @@
5
5
 
6
6
  ## About
7
7
 
8
- - This software is a dedicated server manager (DSM) for Valheim.
9
- - The Valheim DSM is part of the Land of Oz series of software.
10
- - This software is to provide an easy to use container and virtualization free
11
- dedicate server hosting experience.
8
+ **TL;DR:** A terminal-based Valheim server manager that doesn't need Docker, VMs, or a PhD in sysadmin.
9
+
10
+ This is a dedicated server manager for Valheim that runs directly on your machine—no containers, no virtualization, just TypeScript and Node.js. Born from the "Land of Oz" series of server management tools, this project aims to make hosting a Valheim server as painless as possible.
11
+
12
+ Whether you're running a private server for friends or managing a public realm, this tool handles the boring stuff (SteamCMD updates, crash recovery, config management) so you can focus on the Viking stuff (building, exploring, dying to Deathsquitos).
13
+
14
+ [CONTRIBUTING.md](CONTRIBUTING.md) if you want to help make it better.
12
15
 
13
16
  ## Details
14
17
 
15
- - The software is written in TypeScript using Node.js as the runtime
16
- - The DSM program is a rich featured management tool with a Yoga powered TUI.
17
- - The TUI uses Ink which is a React flavored TUI framework
18
- - The motion in the TUI is accelerated by the ASCII Motion app.
19
- - Any AI agent working in this repo has access to the ASCII Motion MCP
20
- server tooling for generating beautiful and efficient animated ascii based
21
- art.
18
+ - **Runtime:** Node.js 22.x with TypeScript
19
+ - **TUI Framework:** Ink 6.x—React, but for your terminal
20
+ - **Layout Engine:** Yoga flexbox—the same layout engine that powers React Native
21
+ - **Animations:** (ASCII Motion)[https://ascii-motion.app/]—why settle for static ASCII art when you can have *animated* ASCII art?
22
+ - **State Management:** Zustand
23
+
22
24
 
23
25
  ## Quick Start
24
26
 
@@ -148,7 +150,7 @@ aesthetic. It prioritizes real-time observability while keeping management tools
148
150
  front and center. Below is a generalized mockup of the DSM TUI built using React
149
151
  via Ink. Motion is created using ASCII Motion.
150
152
 
151
- > The Valheim DSM: Land of Oz interface utilizes a structured three-zone TUI
153
+ > The Valheim DSM interface utilizes a structured three-zone TUI
152
154
  > architecture designed for maximum administrative visibility. A bold animated
153
155
  > ASCII header anchors the top of the screen, followed by a responsive layout
154
156
  > that separates active management from passive monitoring. Where possible, the
@@ -164,11 +166,12 @@ via Ink. Motion is created using ASCII Motion.
164
166
  | Layer | Technology | Purpose |
165
167
  | ---------------- | ---------------- | ------------------------------------------------ |
166
168
  | Runtime | Node.js 22.x | TypeScript-first with tsx execution |
167
- | TUI Framework | Ink 5.x | React-based terminal UI with Yoga flexbox layout |
168
- | State Management | Zustand | Lightweight, React-compatible global state |
169
+ | TUI Framework | Ink 6.x | React-based terminal UI with Yoga flexbox layout |
170
+ | UI Library | React 19.x | Component-based rendering to terminal |
171
+ | State Management | Zustand 5.x | Lightweight, React-compatible global state |
169
172
  | Animation | ASCII Motion MCP | Animated ASCII art for headers and transitions |
170
173
  | Process Control | child_process | Cross-platform subprocess management |
171
- | Configuration | conf | Persistent settings with JSON storage |
174
+ | Configuration | conf 13.x | Persistent settings with JSON storage |
172
175
 
173
176
  ### Directory Structure
174
177
 
@@ -238,7 +241,7 @@ land-of-oz-dsm-valheim/
238
241
  │ ├── config/
239
242
  │ │ ├── mod.ts # Configuration module exports
240
243
  │ │ ├── schema.ts # Zod schemas for validation
241
- │ │ ├── store.ts # Deno KV persistence layer
244
+ │ │ ├── store.ts # conf package persistence layer (JSON)
242
245
  │ │ └── defaults.ts # Default configuration values
243
246
  │ │
244
247
  │ ├── valheim/
@@ -302,9 +305,9 @@ Handles all Steam-related operations:
302
305
 
303
306
  Persistent settings management:
304
307
 
305
- - **Deno KV**: Local key-value storage for settings
306
- - **Zod Validation**: Type-safe schema enforcement
307
- - **Migration Support**: Handle config version upgrades
308
+ - **conf Package**: Cross-platform JSON-based configuration storage
309
+ - **Zod Validation**: Type-safe schema enforcement with runtime validation
310
+ - **Migration Support**: Handle config version upgrades gracefully
308
311
 
309
312
  #### 6. Valheim Integration (`src/valheim/`)
310
313
 
@@ -316,48 +319,78 @@ Game-specific functionality:
316
319
 
317
320
  ### State Flow
318
321
 
319
- ```
320
- ┌─────────────────────────────────────────────────────────────────┐
321
- │ Zustand Store │
322
- │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐
323
- │ │ server │ │ config │ │ logs │ │ ui │ │
324
- │ │ .status │ │ .settings│ │ .entries │ │ .activeScreen │ │
325
- │ │ .pid │ │ .world │ │ .filter │ │ .modalOpen │ │
326
- │ └──────────┘ └──────────┘ └──────────┘ └──────────────────────┘
327
- └─────────────────────────────────────────────────────────────────┘
328
- │ │ │
329
- ▼ ▼ ▼
330
- ┌──────────┐ ┌──────────┐ ┌──────────┐
331
- Process │ │ Deno KV │ │ TUI │
332
- │ Manager │ │ Store │ │ Renderer
333
- └──────────┘ └──────────┘ └──────────┘
334
- ```
335
-
336
- ### TUI Layout Zones
337
-
338
- ```
339
- ┌────────────────────────────────────────────────────────────────────┐
340
- │ ╔═══╗ ╔═══╗ ╔═══╗ │
341
- │ ZONE 1: HEADER ║ L ║ ║ O ║ ║ Z ║ Animated ASCII Title │
342
- │ ╚═══╝ ╚═══╝ ╚═══╝ (ASCII Motion powered) │
343
- ├────────────────────────────────────────────────────────────────────┤
344
- │ │
345
- │ ZONE 2: MAIN CONTENT │
346
- │ ┌──────────────────────┐ ┌─────────────────────────────────────┐
347
- │ │ [1] Dashboard │ │ Server: ● ONLINE │ │
348
- │ │ [2] Settings │ │ Players: 3/10 │ │
349
- │ │ [3] Worlds │ │ World: MyWorld │ │
350
- │ │ [4] Console │ │ Uptime: 4h 23m │ │
351
- │ │ [Q] Quit │ │ │ │
352
- │ └──────────────────────┘ └─────────────────────────────────────┘ │
353
- │ │
354
- ├────────────────────────────────────────────────────────────────────┤
355
- │ ZONE 3: LOG FEED │
356
- │ [INFO] Player "Viking01" connected │
357
- │ [INFO] Player "Viking02" connected │
358
- │ [WARN] High memory usage detected │
359
- │ [INFO] World saved successfully │
360
- └────────────────────────────────────────────────────────────────────┘
322
+ ```mermaid
323
+ graph TB
324
+ subgraph "User Interaction Layer"
325
+ TUI["TUI Components (Ink/React)"]
326
+ CLI["CLI Commands"]
327
+ end
328
+
329
+ subgraph "State Management (Zustand)"
330
+ Store["Global Store"]
331
+ ServerState["server: {status, pid, players}"]
332
+ ConfigState["config: {settings, world}"]
333
+ LogState["logs: {entries, filter}"]
334
+ UIState["ui: {activeScreen, modal}"]
335
+ Store --> ServerState
336
+ Store --> ConfigState
337
+ Store --> LogState
338
+ Store --> UIState
339
+ end
340
+
341
+ subgraph "Process Management"
342
+ PM["Server Process Manager"]
343
+ WD["Watchdog (Auto-restart)"]
344
+ LS["Log Stream Parser"]
345
+ PM --> WD
346
+ PM --> LS
347
+ end
348
+
349
+ subgraph "Persistence Layer"
350
+ Conf["conf (JSON Storage)"]
351
+ Worlds["World Files (.db/.fwl)"]
352
+ end
353
+
354
+ subgraph "External Systems"
355
+ Steam["SteamCMD"]
356
+ Valheim["Valheim Server Process"]
357
+ RCON["RCON Client (Optional)"]
358
+ end
359
+
360
+ TUI -->|User Input| Store
361
+ CLI -->|Commands| Store
362
+
363
+ Store -->|Read/Write| Conf
364
+ Store -->|Start/Stop| PM
365
+ Store -->|Send Commands| RCON
366
+
367
+ PM -->|Spawn| Valheim
368
+ PM -->|stdout/stderr| LS
369
+ LS -->|Parsed Logs| LogState
370
+
371
+ Valheim -->|Events| WD
372
+ WD -->|Restart on Crash| PM
373
+
374
+ ConfigState -->|Load| Conf
375
+ Conf -->|Load Worlds| Worlds
376
+
377
+ CLI -->|Install/Update| Steam
378
+ Steam -->|Download| Valheim
379
+
380
+ Store -->|React Updates| TUI
381
+ RCON -.->|Commands| Valheim
382
+
383
+ classDef userLayer fill:#F37A47,stroke:#B63C21,color:#fff
384
+ classDef stateLayer fill:#018DA6,stroke:#01657C,color:#fff
385
+ classDef processLayer fill:#FCF983,stroke:#000,color:#000
386
+ classDef persistLayer fill:#691E11,stroke:#B63C21,color:#fff
387
+ classDef externalLayer fill:#001018,stroke:#01657C,color:#fff
388
+
389
+ class TUI,CLI userLayer
390
+ class Store,ServerState,ConfigState,LogState,UIState stateLayer
391
+ class PM,WD,LS processLayer
392
+ class Conf,Worlds persistLayer
393
+ class Steam,Valheim,RCON externalLayer
361
394
  ```
362
395
 
363
396
  ### Valheim Server Settings
@@ -383,12 +416,12 @@ The DSM exposes all Valheim dedicated server settings through the TUI:
383
416
 
384
417
  ### Platform Support
385
418
 
386
- | Platform | SteamCMD Path | Valheim Install | Config Storage | Notes |
387
- | ------------- | ---------------------------------------- | ------------------------------------------- | --------------------------------------------- | ----- |
388
- | Windows | `%LOCALAPPDATA%\steamcmd` | `steamapps\common\Valheim dedicated server` | `%APPDATA%\valheim-dsm` | Fully supported |
389
- | macOS | `~/Library/Application Support/steamcmd` | `steamapps/common/Valheim dedicated server` | `~/Library/Application Support/valheim-dsm` | Fully supported |
390
- | Linux (Ubuntu)| `~/.local/share/steamcmd` | `steamapps/common/Valheim dedicated server` | `~/.config/valheim-dsm` | **Requires 32-bit libs** (see Installation) |
391
- | Linux (Other) | `~/.local/share/steamcmd` | `steamapps/common/Valheim dedicated server` | `~/.config/valheim-dsm` | Fully supported |
419
+ | Platform | SteamCMD Path | Valheim Install | Config Storage | Notes |
420
+ | ------------- | ---------------------------------------- | ------------------------------------------- | ------------------------------------------- | ----- |
421
+ | Windows | `%LOCALAPPDATA%\steamcmd` | `steamapps\common\Valheim dedicated server` | `%APPDATA%\oz-valheim` | Fully supported |
422
+ | macOS | `~/Library/Application Support/steamcmd` | `steamapps/common/Valheim dedicated server` | `~/Library/Application Support/oz-valheim` | Fully supported |
423
+ | Linux (Ubuntu)| `~/.local/share/steamcmd` | `steamapps/common/Valheim dedicated server` | `~/.config/oz-valheim` | **Requires 32-bit libs** (see Installation) |
424
+ | Linux (Other) | `~/.local/share/steamcmd` | `steamapps/common/Valheim dedicated server` | `~/.config/oz-valheim` | Fully supported |
392
425
 
393
426
  ### Development
394
427
 
package/dist/main.js CHANGED
@@ -4878,7 +4878,7 @@ import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useSta
4878
4878
  // package.json
4879
4879
  var package_default = {
4880
4880
  name: "valheim-oz-dsm",
4881
- version: "1.8.0",
4881
+ version: "1.8.2",
4882
4882
  description: "Land of OZ - Valheim Dedicated Server Manager",
4883
4883
  type: "module",
4884
4884
  bin: {
@@ -45131,22 +45131,29 @@ function useServer() {
45131
45131
  }, 1e3);
45132
45132
  return () => clearInterval(interval);
45133
45133
  }, [status, actions]);
45134
+ const rconEnabled = rcon.enabled;
45135
+ const rconPort = rcon.port;
45136
+ const rconPassword = rcon.password;
45137
+ const rconTimeout = rcon.timeout;
45138
+ const rconAutoReconnect = rcon.autoReconnect;
45139
+ const rconInitialized = useRef3(false);
45134
45140
  useEffect8(() => {
45135
- if (!rcon.enabled) {
45141
+ if (!rconEnabled) {
45136
45142
  if (rconManager.isConnected()) {
45137
45143
  rconManager.disconnect();
45138
45144
  actions.setRconConnected(false);
45139
45145
  }
45146
+ rconInitialized.current = false;
45140
45147
  return;
45141
45148
  }
45142
45149
  rconManager.initialize(
45143
45150
  {
45144
45151
  host: "localhost",
45145
- port: rcon.port,
45146
- password: rcon.password,
45147
- timeout: rcon.timeout,
45148
- enabled: rcon.enabled,
45149
- autoReconnect: rcon.autoReconnect
45152
+ port: rconPort,
45153
+ password: rconPassword,
45154
+ timeout: rconTimeout,
45155
+ enabled: rconEnabled,
45156
+ autoReconnect: rconAutoReconnect
45150
45157
  },
45151
45158
  {
45152
45159
  onConnectionStateChange: (state) => {
@@ -45167,12 +45174,23 @@ function useServer() {
45167
45174
  // Poll every 10 seconds
45168
45175
  }
45169
45176
  );
45177
+ rconInitialized.current = true;
45170
45178
  return () => {
45171
- rconManager.disconnect();
45179
+ if (rconInitialized.current) {
45180
+ rconManager.disconnect();
45181
+ rconInitialized.current = false;
45182
+ }
45172
45183
  };
45173
- }, [rcon, actions]);
45184
+ }, [
45185
+ rconEnabled,
45186
+ rconPort,
45187
+ rconPassword,
45188
+ rconTimeout,
45189
+ rconAutoReconnect,
45190
+ actions
45191
+ ]);
45174
45192
  useEffect8(() => {
45175
- if (status === "online" && rcon.enabled && !rconManager.isConnected()) {
45193
+ if (status === "online" && rconEnabled && !rconManager.isConnected()) {
45176
45194
  const timer = setTimeout(() => {
45177
45195
  rconManager.connect().catch((error2) => {
45178
45196
  actions.addLog("warn", `RCON connection failed: ${error2}`);
@@ -45183,7 +45201,7 @@ function useServer() {
45183
45201
  if (status === "offline" && rconManager.isConnected()) {
45184
45202
  rconManager.disconnect();
45185
45203
  }
45186
- }, [status, rcon.enabled, actions]);
45204
+ }, [status, rconEnabled, actions]);
45187
45205
  return {
45188
45206
  status,
45189
45207
  start,