omegga 1.15.0 → 1.16.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Latest
4
4
 
5
+ ## 1.16.0 - 2026-09-01
6
+
7
+ A Pterodactyl egg for running Omegga under a game panel.
8
+
9
+ - Add a Pterodactyl egg at [`docker/pterodactyl/egg-omegga.json`](https://github.com/brickadia-community/omegga/blob/master/docker/pterodactyl/egg-omegga.json), documented at https://omegga.brickadia.dev/guides/pterodactyl.html
10
+ - The container entrypoint adopts the `STARTUP` command, `HOME`, and working directory Wings expects an image to supply
11
+ - `VERBOSE` now works; it was documented but never read
12
+ - `BRICKADIA_DEBUG` and `SKIP_STEAMCMD_PROMPT` parse their value, so `BRICKADIA_DEBUG=false` no longer enables debug logging
13
+ - Add `OMEGGA_NONINTERACTIVE` to exit instead of waiting at a prompt nothing can answer, on by default when stdin is not a terminal
14
+ - Fix `omegga auth` exiting 0 when authentication failed
15
+
5
16
  ## 1.15.0 - 2026-08-31
6
17
 
7
18
  A Prometheus metrics endpoint, dashboards for it in the web UI, and the README split into a documentation site.
package/README.md CHANGED
@@ -68,7 +68,7 @@ omegga
68
68
 
69
69
  Omegga will prompt for credentials as necessary and only stores the auth tokens brickadia generates on login. **Omegga does not store your password**.
70
70
 
71
- To run it in a container instead, see [Containers](docs/containers.md). For the long version, including troubleshooting, see [Installing](docs/install/README.md).
71
+ To run it in a container instead, see [Containers](docs/containers.md), or [Pterodactyl](docs/guides/pterodactyl.md) to run it as an egg under a Pterodactyl panel. For the long version, including troubleshooting, see [Installing](docs/install/README.md).
72
72
 
73
73
  ## Documentation
74
74
 
@@ -78,6 +78,7 @@ Everything below is also published as a book at
78
78
  | Setting up | |
79
79
  | --- | --- |
80
80
  | [Installing](docs/install/README.md) | [linux](docs/install/linux.md), [WSL](docs/install/wsl.md), or a [container](docs/containers.md) |
81
+ | [Pterodactyl](docs/guides/pterodactyl.md) | running omegga as a Pterodactyl egg |
81
82
  | [Running](docs/running.md) | starting a server and keeping it updated |
82
83
  | [Configuration](docs/config.md) | `omegga-config.yml`, field by field |
83
84
  | [Environment variables](docs/env.md) | what omegga reads from the environment |
@@ -119,3 +120,19 @@ npm run dist # build the web ui, omegga's typescript, and omegga.d.ts
119
120
  `npm run lint`, `npm run typecheck`, and `npm test` are what CI runs. The API
120
121
  pages under `docs/api` are generated from the JSDoc in `src/`; run
121
122
  `npm run docs:api` after changing those comments.
123
+
124
+ ### Release Process
125
+
126
+ 1. **Bump**: Bump `version` in `package.json` and sync the lockfile with
127
+ `npm i --package-lock-only`.
128
+ 2. **Changelog**: Move the `## Latest` entries in `CHANGELOG.md` under a
129
+ `## <version> - <date>` heading.
130
+ 3. **Pterodactyl**: Point the pinned image in `docker/pterodactyl/egg-omegga.json` at the new
131
+ `<major>.<minor>`. Releases only move `latest`, `<major>`, and
132
+ `<major>.<minor>`, so a pin left on the previous minor is frozen on an
133
+ image that will never be rebuilt, while still being selectable in the
134
+ panel.
135
+ 4. **Linters**: `just check`
136
+ 5. **Commit**: Ensure everything is pushed
137
+ 6. **Deploy Container**: `just tag` to push tag the image to ghcr.
138
+ 7. **Deploy NPM**: `just publish` to build `dist/` and publish the package to npm.
package/dist/cli/auth.js CHANGED
@@ -2,12 +2,28 @@
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
3
  const softconfig = require("../softconfig.js");
4
4
  const auth = require("../omegga/auth.js");
5
+ const env = require("../util/env.js");
5
6
  const file = require("../util/file.js");
6
7
  require("colors");
7
8
  const fs = require("node:fs");
8
9
  const path = require("node:path");
9
10
  const prompts = require("prompts");
10
11
  const AUTH_PATH = path.join(softconfig.default.CONFIG_HOME, softconfig.default.CONFIG_AUTH_DIR);
12
+ function failNonInteractive() {
13
+ console.error(
14
+ "!>".red,
15
+ "No stored auth files and no hosting token, and there is no terminal to prompt on"
16
+ );
17
+ console.error(
18
+ "!>".red,
19
+ "Generate a hosting token at https://brickadia.com/account/tokens, then set",
20
+ "BRICKADIA_TOKEN".yellow,
21
+ "or",
22
+ "credentials.token".yellow,
23
+ "in omegga-config.yml"
24
+ );
25
+ return false;
26
+ }
11
27
  async function credentialPrompt() {
12
28
  console.log(
13
29
  ">>".green,
@@ -41,6 +57,7 @@ async function authFromPrompt({
41
57
  }) {
42
58
  let files;
43
59
  if (isSteam || !email || !password) {
60
+ if (env.isNonInteractive()) return failNonInteractive();
44
61
  const { authType } = await prompts({
45
62
  type: "select",
46
63
  name: "authType",
@@ -83,6 +100,7 @@ async function authFromPrompt({
83
100
  }
84
101
  }
85
102
  if (!email || !password || !isSteam) {
103
+ if (env.isNonInteractive()) return failNonInteractive();
86
104
  try {
87
105
  [email, password] = await credentialPrompt();
88
106
  } catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sources":["../../src/cli/auth.ts"],"sourcesContent":["import soft from '@/softconfig';\nimport { genAuthFiles, writeAuthFiles } from '@omegga/auth';\nimport * as file from '@util/file';\nimport 'colors';\nimport fs, { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport prompts from 'prompts';\n\nexport const AUTH_PATH = path.join(soft.CONFIG_HOME, soft.CONFIG_AUTH_DIR);\n\n// async function to prompt for credentials\nasync function credentialPrompt() {\n console.log(\n '>>'.green,\n 'Enter',\n 'Brickadia'.green.underline,\n 'credentials (not stored)',\n );\n\n const response = await prompts([\n {\n type: 'text',\n name: 'email',\n message: 'Email',\n },\n {\n type: 'password',\n name: 'password',\n message: 'Password',\n },\n ]);\n\n return [response.email, response.password];\n}\n\nasync function authFromPrompt({\n email,\n password,\n debug = false,\n isSteam,\n branch,\n authDir,\n savedDir,\n launchArgs,\n}: {\n email?: string | null;\n password?: string | null;\n debug?: boolean;\n isSteam?: boolean;\n branch?: string;\n authDir?: string;\n savedDir?: string;\n launchArgs?: string;\n}) {\n let files: Record<string, Buffer> | null;\n\n if (isSteam || !email || !password) {\n // Prompt user to pick to select username/password or Auth Token\n const { authType } = await prompts({\n type: 'select',\n name: 'authType',\n message: 'Select authentication method',\n choices: [\n { title: 'Hosting Token', value: 'token' },\n { title: 'Username/Password', value: 'credentials' },\n ],\n });\n\n if (!authType) {\n console.error('!>'.red, 'No authentication method selected');\n return false;\n }\n\n if (authType === 'token') {\n // Prompt for hosting token\n const { token } = await prompts({\n type: 'password',\n name: 'token',\n message:\n 'Paste your server hosting token (generate one at https://brickadia.com/account/tokens)',\n validate: value => (value ? true : 'Token is required'),\n });\n\n if (!token) {\n console.error('!>'.red, 'Hosting token is required');\n return false;\n }\n\n // Write to global token file\n try {\n console.log('>>'.green, 'Storing hosting token...');\n fs.writeFileSync(soft.GLOBAL_TOKEN, token.trim());\n } catch (err) {\n console.error('!>'.red, 'Error writing hosting token to config\\n', err);\n return false;\n }\n\n return true;\n }\n\n if (isSteam) {\n console.error(\n '!>'.red,\n 'Launching with steam requires a hosting token right now.',\n );\n return false;\n }\n\n // Non-steam password auth is handled below\n }\n\n if (!email || !password || !isSteam) {\n // prompt for user credentials\n try {\n [email, password] = await credentialPrompt();\n } catch (err) {\n console.error('!>'.red, 'Error prompting credentials\\n', err);\n return false;\n }\n }\n\n if (!email || !password) {\n console.error('!>'.red, 'Email and password are required');\n return false;\n }\n\n // generate auth tokens\n console.log('>>'.green, 'Generating auth tokens...');\n const timeout = setTimeout(() => {\n console.log('>>'.green, 'Probably also installing the game...');\n }, 10000);\n try {\n files = await genAuthFiles(email, password, {\n debug,\n branch,\n authDir,\n savedDir,\n launchArgs,\n });\n clearTimeout(timeout);\n } catch (err) {\n clearTimeout(timeout);\n console.error('!>'.red, 'Error generating tokens:', err);\n return false;\n }\n\n if (!files) {\n console.error('!>'.red, 'Authentication Failed');\n return;\n }\n\n // save the tokens to the config path (will be copied when omegga starts)\n try {\n console.log('>>'.green, 'Storing auth tokens...');\n const authPath = path.join(\n soft.CONFIG_HOME,\n savedDir && savedDir !== soft.CONFIG_SAVED_DIR ? savedDir : '',\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n file.mkdir(authPath);\n writeAuthFiles(authPath, files);\n } catch (err) {\n console.error('!>'.red, 'Error writing tokens to config\\n', err);\n return false;\n }\n\n console.log('>>'.green, 'Auth tokens successfully generated!');\n return true;\n}\n\n// check if auth files exist\nfunction authExists(dir?: string) {\n return soft.BRICKADIA_AUTH_FILES.every(f =>\n fs.existsSync(path.join(dir ?? AUTH_PATH, f)),\n );\n}\n\n// delete auth files stored in config\n// delete auth files stored in config\nfunction deleteAuthFiles(dir?: string) {\n const isConfigHome = dir && dir.startsWith(soft.CONFIG_HOME);\n // will not delete files outside of the config home\n if (dir && !isConfigHome) return;\n file.rmdir(dir ?? AUTH_PATH);\n\n // Remove the global auth token\n if (existsSync(soft.GLOBAL_TOKEN)) {\n fs.unlinkSync(soft.GLOBAL_TOKEN);\n }\n}\n\nexport function getGlobalToken() {\n if (!fs.existsSync(soft.GLOBAL_TOKEN)) return null;\n return fs.readFileSync(soft.GLOBAL_TOKEN, 'utf-8').trim();\n}\n\nexport const prompt = authFromPrompt;\nexport const exists = authExists;\nexport const clean = deleteAuthFiles;\n\nexport default {\n AUTH_PATH,\n prompt,\n exists,\n clean,\n getGlobalToken,\n};\n"],"names":["soft","genAuthFiles","file.mkdir","writeAuthFiles","file.rmdir","existsSync"],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sources":["../../src/cli/auth.ts"],"sourcesContent":["import soft from '@/softconfig';\nimport { genAuthFiles, writeAuthFiles } from '@omegga/auth';\nimport { isNonInteractive } from '@util/env';\nimport * as file from '@util/file';\nimport 'colors';\nimport fs, { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport prompts from 'prompts';\n\nexport const AUTH_PATH = path.join(soft.CONFIG_HOME, soft.CONFIG_AUTH_DIR);\n\n/**\n * Refuse to authenticate rather than opening a prompt nothing can answer.\n *\n * Reaching a prompt on such a host is worse than failing: omegga blocks\n * before it logs anything a supervisor recognises as a start, so the failure\n * shows up as a startup timeout with no cause in the log.\n */\nfunction failNonInteractive() {\n console.error(\n '!>'.red,\n 'No stored auth files and no hosting token, and there is no terminal to prompt on',\n );\n console.error(\n '!>'.red,\n 'Generate a hosting token at https://brickadia.com/account/tokens, then set',\n 'BRICKADIA_TOKEN'.yellow,\n 'or',\n 'credentials.token'.yellow,\n 'in omegga-config.yml',\n );\n return false;\n}\n\n// async function to prompt for credentials\nasync function credentialPrompt() {\n console.log(\n '>>'.green,\n 'Enter',\n 'Brickadia'.green.underline,\n 'credentials (not stored)',\n );\n\n const response = await prompts([\n {\n type: 'text',\n name: 'email',\n message: 'Email',\n },\n {\n type: 'password',\n name: 'password',\n message: 'Password',\n },\n ]);\n\n return [response.email, response.password];\n}\n\nasync function authFromPrompt({\n email,\n password,\n debug = false,\n isSteam,\n branch,\n authDir,\n savedDir,\n launchArgs,\n}: {\n email?: string | null;\n password?: string | null;\n debug?: boolean;\n isSteam?: boolean;\n branch?: string;\n authDir?: string;\n savedDir?: string;\n launchArgs?: string;\n}) {\n let files: Record<string, Buffer> | null;\n\n if (isSteam || !email || !password) {\n if (isNonInteractive()) return failNonInteractive();\n\n // Prompt user to pick to select username/password or Auth Token\n const { authType } = await prompts({\n type: 'select',\n name: 'authType',\n message: 'Select authentication method',\n choices: [\n { title: 'Hosting Token', value: 'token' },\n { title: 'Username/Password', value: 'credentials' },\n ],\n });\n\n if (!authType) {\n console.error('!>'.red, 'No authentication method selected');\n return false;\n }\n\n if (authType === 'token') {\n // Prompt for hosting token\n const { token } = await prompts({\n type: 'password',\n name: 'token',\n message:\n 'Paste your server hosting token (generate one at https://brickadia.com/account/tokens)',\n validate: value => (value ? true : 'Token is required'),\n });\n\n if (!token) {\n console.error('!>'.red, 'Hosting token is required');\n return false;\n }\n\n // Write to global token file\n try {\n console.log('>>'.green, 'Storing hosting token...');\n fs.writeFileSync(soft.GLOBAL_TOKEN, token.trim());\n } catch (err) {\n console.error('!>'.red, 'Error writing hosting token to config\\n', err);\n return false;\n }\n\n return true;\n }\n\n if (isSteam) {\n console.error(\n '!>'.red,\n 'Launching with steam requires a hosting token right now.',\n );\n return false;\n }\n\n // Non-steam password auth is handled below\n }\n\n if (!email || !password || !isSteam) {\n if (isNonInteractive()) return failNonInteractive();\n\n // prompt for user credentials\n try {\n [email, password] = await credentialPrompt();\n } catch (err) {\n console.error('!>'.red, 'Error prompting credentials\\n', err);\n return false;\n }\n }\n\n if (!email || !password) {\n console.error('!>'.red, 'Email and password are required');\n return false;\n }\n\n // generate auth tokens\n console.log('>>'.green, 'Generating auth tokens...');\n const timeout = setTimeout(() => {\n console.log('>>'.green, 'Probably also installing the game...');\n }, 10000);\n try {\n files = await genAuthFiles(email, password, {\n debug,\n branch,\n authDir,\n savedDir,\n launchArgs,\n });\n clearTimeout(timeout);\n } catch (err) {\n clearTimeout(timeout);\n console.error('!>'.red, 'Error generating tokens:', err);\n return false;\n }\n\n if (!files) {\n console.error('!>'.red, 'Authentication Failed');\n return;\n }\n\n // save the tokens to the config path (will be copied when omegga starts)\n try {\n console.log('>>'.green, 'Storing auth tokens...');\n const authPath = path.join(\n soft.CONFIG_HOME,\n savedDir && savedDir !== soft.CONFIG_SAVED_DIR ? savedDir : '',\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n file.mkdir(authPath);\n writeAuthFiles(authPath, files);\n } catch (err) {\n console.error('!>'.red, 'Error writing tokens to config\\n', err);\n return false;\n }\n\n console.log('>>'.green, 'Auth tokens successfully generated!');\n return true;\n}\n\n// check if auth files exist\nfunction authExists(dir?: string) {\n return soft.BRICKADIA_AUTH_FILES.every(f =>\n fs.existsSync(path.join(dir ?? AUTH_PATH, f)),\n );\n}\n\n// delete auth files stored in config\n// delete auth files stored in config\nfunction deleteAuthFiles(dir?: string) {\n const isConfigHome = dir && dir.startsWith(soft.CONFIG_HOME);\n // will not delete files outside of the config home\n if (dir && !isConfigHome) return;\n file.rmdir(dir ?? AUTH_PATH);\n\n // Remove the global auth token\n if (existsSync(soft.GLOBAL_TOKEN)) {\n fs.unlinkSync(soft.GLOBAL_TOKEN);\n }\n}\n\nexport function getGlobalToken() {\n if (!fs.existsSync(soft.GLOBAL_TOKEN)) return null;\n return fs.readFileSync(soft.GLOBAL_TOKEN, 'utf-8').trim();\n}\n\nexport const prompt = authFromPrompt;\nexport const exists = authExists;\nexport const clean = deleteAuthFiles;\n\nexport default {\n AUTH_PATH,\n prompt,\n exists,\n clean,\n getGlobalToken,\n};\n"],"names":["soft","isNonInteractive","genAuthFiles","file.mkdir","writeAuthFiles","file.rmdir","existsSync"],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
3
  const logger = require("../logger.js");
4
4
  const softconfig = require("../softconfig.js");
5
+ const env = require("../util/env.js");
5
6
  require("colors");
6
7
  const Configstore = require("configstore");
7
8
  const fs = require("node:fs");
@@ -46,15 +47,6 @@ function parseEnvPort(name) {
46
47
  logger.default.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not a port`);
47
48
  return void 0;
48
49
  }
49
- function parseEnvBool(name) {
50
- const raw = process.env[name];
51
- if (!raw) return void 0;
52
- const value = raw.trim().toLowerCase();
53
- if (["true", "1", "yes", "on"].includes(value)) return true;
54
- if (["false", "0", "no", "off"].includes(value)) return false;
55
- logger.default.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not a boolean`);
56
- return void 0;
57
- }
58
50
  function parseEnvSeconds(name) {
59
51
  const raw = process.env[name];
60
52
  if (!raw) return void 0;
@@ -91,7 +83,7 @@ function applyPortOverrides(conf) {
91
83
  return conf;
92
84
  }
93
85
  function applyMetricsOverrides(conf) {
94
- const enabled = parseEnvBool("METRICS_ENABLED");
86
+ const enabled = env.parseEnvBool("METRICS_ENABLED");
95
87
  if (enabled != null) conf.metrics = { ...conf.metrics, enabled };
96
88
  const bind = process.env.METRICS_BIND?.trim();
97
89
  if (bind) conf.metrics = { ...conf.metrics, bind };
@@ -104,7 +96,7 @@ function applyMetricsOverrides(conf) {
104
96
  prometheus[key] = value;
105
97
  touched = true;
106
98
  };
107
- set("enabled", parseEnvBool("METRICS_PROMETHEUS_ENABLED"));
99
+ set("enabled", env.parseEnvBool("METRICS_PROMETHEUS_ENABLED"));
108
100
  set("url", parseEnvUrl("METRICS_PROMETHEUS_URL"));
109
101
  set("instance", parseEnvLabel("METRICS_PROMETHEUS_INSTANCE"));
110
102
  set("timeout", parseEnvSeconds("METRICS_PROMETHEUS_TIMEOUT"));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/config/index.ts"],"sourcesContent":["import Logger from '@/logger';\nimport soft, { METRICS_DEFAULTS } from '@/softconfig';\nimport 'colors';\nimport Configstore from 'configstore';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport format_js from './formats/format_js';\nimport format_yaml from './formats/format_yml';\nimport reader from './reader';\nimport { type IConfig, type IConfigFormat } from './types';\nimport writer from './writer';\nexport * from './types';\n\nexport const store = new Configstore(\n soft.PROJECT_NAME,\n {\n defaultOmegga: '.',\n legacyBin: '',\n },\n {\n globalConfigPath: true,\n },\n);\n\n// find all format_EXT.js files in the formats path\nconst formats: IConfigFormat[] = [format_js, format_yaml];\n\n// create read/write funcs for the provided formats\nexport const defaultConfig: IConfig = {\n omegga: {\n webui: true,\n port: process.env.OMEGGA_PORT\n ? Number(process.env.OMEGGA_PORT)\n : soft.DEFAULT_PORT,\n https: true,\n },\n server: {\n port: process.env.BRICKADIA_PORT\n ? Number(process.env.BRICKADIA_PORT)\n : 7777,\n map: 'Plate',\n },\n metrics: {\n enabled: false,\n bind: METRICS_DEFAULTS.bind,\n port: METRICS_DEFAULTS.port,\n },\n};\n\n/** parse a port from the environment, warning (and ignoring) when it isn't one */\nfunction parseEnvPort(name: string) {\n const raw = process.env[name];\n if (!raw) return undefined;\n const port = Number(raw);\n if (Number.isInteger(port) && port > 0 && port < 65536) return port;\n Logger.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not a port`);\n return undefined;\n}\n\n/** parse a boolean from the environment, warning (and ignoring) when it isn't one */\nfunction parseEnvBool(name: string) {\n const raw = process.env[name];\n if (!raw) return undefined;\n const value = raw.trim().toLowerCase();\n if (['true', '1', 'yes', 'on'].includes(value)) return true;\n if (['false', '0', 'no', 'off'].includes(value)) return false;\n Logger.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not a boolean`);\n return undefined;\n}\n\n/** parse a positive number of seconds, warning (and ignoring) when it isn't one */\nfunction parseEnvSeconds(name: string) {\n const raw = process.env[name];\n if (!raw) return undefined;\n const seconds = Number(raw);\n if (Number.isFinite(seconds) && seconds > 0) return seconds;\n Logger.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not a duration`);\n return undefined;\n}\n\n/** parse an http(s) URL, warning (and ignoring) when it isn't one */\nfunction parseEnvUrl(name: string) {\n const raw = process.env[name]?.trim();\n if (!raw) return undefined;\n try {\n const url = new URL(raw);\n if (url.protocol === 'http:' || url.protocol === 'https:') return raw;\n } catch {\n // fall through to the warning\n }\n Logger.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not an http URL`);\n return undefined;\n}\n\n/**\n * Parse a prometheus label value. The same restriction the config schema\n * applies, repeated here because environment overrides land after the schema\n * has already validated the file.\n */\nfunction parseEnvLabel(name: string) {\n const raw = process.env[name]?.trim();\n if (!raw) return undefined;\n if (/^[A-Za-z0-9_.:-]+$/.test(raw)) return raw;\n Logger.warnp(\n `Ignoring ${name.yellow}: ${raw.yellow} is not a valid label value`,\n );\n return undefined;\n}\n\n/**\n * Apply `OMEGGA_PORT` and `BRICKADIA_PORT` on top of a loaded config. A\n * container's config file lives in a mounted volume that can't be templated,\n * so the environment has to be able to win.\n */\nexport function applyPortOverrides(conf: IConfig): IConfig {\n const omeggaPort = parseEnvPort('OMEGGA_PORT');\n if (omeggaPort) conf.omegga = { ...conf.omegga, port: omeggaPort };\n\n const serverPort = parseEnvPort('BRICKADIA_PORT');\n if (serverPort) conf.server = { ...conf.server, port: serverPort };\n\n return conf;\n}\n\n/**\n * Apply `METRICS_ENABLED`, `METRICS_BIND`, and `METRICS_PORT` on top of a\n * loaded config, for the same reason `applyPortOverrides` exists: a container\n * can't template the config file in its mounted volume.\n */\nexport function applyMetricsOverrides(conf: IConfig): IConfig {\n const enabled = parseEnvBool('METRICS_ENABLED');\n if (enabled != null) conf.metrics = { ...conf.metrics, enabled };\n\n const bind = process.env.METRICS_BIND?.trim();\n if (bind) conf.metrics = { ...conf.metrics, bind };\n\n const port = parseEnvPort('METRICS_PORT');\n if (port) conf.metrics = { ...conf.metrics, port };\n\n const prometheus = { ...conf.metrics?.prometheus };\n let touched = false;\n const set = <K extends keyof typeof prometheus>(\n key: K,\n value: (typeof prometheus)[K] | undefined,\n ) => {\n if (value == null) return;\n prometheus[key] = value;\n touched = true;\n };\n\n set('enabled', parseEnvBool('METRICS_PROMETHEUS_ENABLED'));\n set('url', parseEnvUrl('METRICS_PROMETHEUS_URL'));\n set('instance', parseEnvLabel('METRICS_PROMETHEUS_INSTANCE'));\n set('timeout', parseEnvSeconds('METRICS_PROMETHEUS_TIMEOUT'));\n\n if (touched) conf.metrics = { ...conf.metrics, prometheus };\n\n return conf;\n}\n\n// Writes save data to a file\nexport const write = writer(formats);\n\n// reads save data from a file\nexport const read = reader(formats);\n\n// open config at a specified path\nexport const find = (dir = '.') => {\n // find the first config file matching these config file names\n for (const f of soft.CONFIG_FILENAMES) {\n for (const { extension } of formats) {\n const file = path.join(dir, f + '.' + extension);\n if (fs.existsSync(file)) return file;\n }\n }\n\n return undefined;\n};\n\nexport * from './types';\n\nexport default {\n store,\n write,\n read,\n find,\n defaultConfig,\n formats,\n applyPortOverrides,\n applyMetricsOverrides,\n};\n"],"names":["soft","format_js","format_yaml","METRICS_DEFAULTS","Logger","writer","reader"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/config/index.ts"],"sourcesContent":["import Logger from '@/logger';\nimport soft, { METRICS_DEFAULTS } from '@/softconfig';\nimport { parseEnvBool } from '@util/env';\nimport 'colors';\nimport Configstore from 'configstore';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport format_js from './formats/format_js';\nimport format_yaml from './formats/format_yml';\nimport reader from './reader';\nimport { type IConfig, type IConfigFormat } from './types';\nimport writer from './writer';\nexport * from './types';\n\nexport const store = new Configstore(\n soft.PROJECT_NAME,\n {\n defaultOmegga: '.',\n legacyBin: '',\n },\n {\n globalConfigPath: true,\n },\n);\n\n// find all format_EXT.js files in the formats path\nconst formats: IConfigFormat[] = [format_js, format_yaml];\n\n// create read/write funcs for the provided formats\nexport const defaultConfig: IConfig = {\n omegga: {\n webui: true,\n port: process.env.OMEGGA_PORT\n ? Number(process.env.OMEGGA_PORT)\n : soft.DEFAULT_PORT,\n https: true,\n },\n server: {\n port: process.env.BRICKADIA_PORT\n ? Number(process.env.BRICKADIA_PORT)\n : 7777,\n map: 'Plate',\n },\n metrics: {\n enabled: false,\n bind: METRICS_DEFAULTS.bind,\n port: METRICS_DEFAULTS.port,\n },\n};\n\n/** parse a port from the environment, warning (and ignoring) when it isn't one */\nfunction parseEnvPort(name: string) {\n const raw = process.env[name];\n if (!raw) return undefined;\n const port = Number(raw);\n if (Number.isInteger(port) && port > 0 && port < 65536) return port;\n Logger.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not a port`);\n return undefined;\n}\n\n/** parse a positive number of seconds, warning (and ignoring) when it isn't one */\nfunction parseEnvSeconds(name: string) {\n const raw = process.env[name];\n if (!raw) return undefined;\n const seconds = Number(raw);\n if (Number.isFinite(seconds) && seconds > 0) return seconds;\n Logger.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not a duration`);\n return undefined;\n}\n\n/** parse an http(s) URL, warning (and ignoring) when it isn't one */\nfunction parseEnvUrl(name: string) {\n const raw = process.env[name]?.trim();\n if (!raw) return undefined;\n try {\n const url = new URL(raw);\n if (url.protocol === 'http:' || url.protocol === 'https:') return raw;\n } catch {\n // fall through to the warning\n }\n Logger.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not an http URL`);\n return undefined;\n}\n\n/**\n * Parse a prometheus label value. The same restriction the config schema\n * applies, repeated here because environment overrides land after the schema\n * has already validated the file.\n */\nfunction parseEnvLabel(name: string) {\n const raw = process.env[name]?.trim();\n if (!raw) return undefined;\n if (/^[A-Za-z0-9_.:-]+$/.test(raw)) return raw;\n Logger.warnp(\n `Ignoring ${name.yellow}: ${raw.yellow} is not a valid label value`,\n );\n return undefined;\n}\n\n/**\n * Apply `OMEGGA_PORT` and `BRICKADIA_PORT` on top of a loaded config. A\n * container's config file lives in a mounted volume that can't be templated,\n * so the environment has to be able to win.\n */\nexport function applyPortOverrides(conf: IConfig): IConfig {\n const omeggaPort = parseEnvPort('OMEGGA_PORT');\n if (omeggaPort) conf.omegga = { ...conf.omegga, port: omeggaPort };\n\n const serverPort = parseEnvPort('BRICKADIA_PORT');\n if (serverPort) conf.server = { ...conf.server, port: serverPort };\n\n return conf;\n}\n\n/**\n * Apply `METRICS_ENABLED`, `METRICS_BIND`, and `METRICS_PORT` on top of a\n * loaded config, for the same reason `applyPortOverrides` exists: a container\n * can't template the config file in its mounted volume.\n */\nexport function applyMetricsOverrides(conf: IConfig): IConfig {\n const enabled = parseEnvBool('METRICS_ENABLED');\n if (enabled != null) conf.metrics = { ...conf.metrics, enabled };\n\n const bind = process.env.METRICS_BIND?.trim();\n if (bind) conf.metrics = { ...conf.metrics, bind };\n\n const port = parseEnvPort('METRICS_PORT');\n if (port) conf.metrics = { ...conf.metrics, port };\n\n const prometheus = { ...conf.metrics?.prometheus };\n let touched = false;\n const set = <K extends keyof typeof prometheus>(\n key: K,\n value: (typeof prometheus)[K] | undefined,\n ) => {\n if (value == null) return;\n prometheus[key] = value;\n touched = true;\n };\n\n set('enabled', parseEnvBool('METRICS_PROMETHEUS_ENABLED'));\n set('url', parseEnvUrl('METRICS_PROMETHEUS_URL'));\n set('instance', parseEnvLabel('METRICS_PROMETHEUS_INSTANCE'));\n set('timeout', parseEnvSeconds('METRICS_PROMETHEUS_TIMEOUT'));\n\n if (touched) conf.metrics = { ...conf.metrics, prometheus };\n\n return conf;\n}\n\n// Writes save data to a file\nexport const write = writer(formats);\n\n// reads save data from a file\nexport const read = reader(formats);\n\n// open config at a specified path\nexport const find = (dir = '.') => {\n // find the first config file matching these config file names\n for (const f of soft.CONFIG_FILENAMES) {\n for (const { extension } of formats) {\n const file = path.join(dir, f + '.' + extension);\n if (fs.existsSync(file)) return file;\n }\n }\n\n return undefined;\n};\n\nexport * from './types';\n\nexport default {\n store,\n write,\n read,\n find,\n defaultConfig,\n formats,\n applyPortOverrides,\n applyMetricsOverrides,\n};\n"],"names":["soft","format_js","format_yaml","METRICS_DEFAULTS","Logger","parseEnvBool","writer","reader"],"mappings":"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"}
package/dist/main.js CHANGED
@@ -6,6 +6,7 @@ const version$1 = require("./omegga/matchers/version.js");
6
6
  const server = require("./omegga/server.js");
7
7
  const file = require("./util/file.js");
8
8
  const container = require("./util/container.js");
9
+ const env = require("./util/env.js");
9
10
  require("colors");
10
11
  const commander = require("commander");
11
12
  const dotenv = require("dotenv");
@@ -39,20 +40,25 @@ const createDefaultConfig = () => {
39
40
  file.mkdir("plugins");
40
41
  return index.defaultConfig;
41
42
  };
43
+ const isVerbose = (flag) => Boolean(flag) || env.parseEnvBool("VERBOSE") === true;
44
+ const isDebug = (flag) => Boolean(flag) || env.parseEnvBool("BRICKADIA_DEBUG") === true;
42
45
  const program = commander.description(version.PKG.description).version(version.VERSION).option(
43
46
  "-d, --debug",
44
47
  "Print all console logs rather than just chat messages (env: BRICKADIA_DEBUG)"
45
48
  ).option(
46
49
  "-u, --update",
47
50
  "Check for brickadia updates (on steam) and install them if available"
48
- ).option("-v, --verbose", "Print extra messages for debugging purposes").action(async () => {
51
+ ).option(
52
+ "-v, --verbose",
53
+ "Print extra messages for debugging purposes (env: VERBOSE)"
54
+ ).action(async () => {
49
55
  const { verbose, update } = program.opts();
50
- const debug = Boolean(program.opts().debug || process.env.BRICKADIA_DEBUG);
56
+ const debug = isDebug(program.opts().debug);
51
57
  if (program.args.length > 0) {
52
58
  program.help();
53
59
  process.exit(1);
54
60
  }
55
- logger.default.VERBOSE = Boolean(verbose);
61
+ logger.default.VERBOSE = isVerbose(verbose);
56
62
  let workDir = index.store.get("defaultOmegga");
57
63
  logger.default.verbose("Using working directory", workDir?.yellow);
58
64
  if (index.find(".")) workDir = ".";
@@ -258,10 +264,8 @@ program.command("auth").option("-g, --global", "Remove global auth files").optio
258
264
  global: globalAuth
259
265
  }) => {
260
266
  const { verbose } = program.opts();
261
- const debug = Boolean(
262
- program.opts().debug || process.env.BRICKADIA_DEBUG
263
- );
264
- logger.default.VERBOSE = Boolean(verbose);
267
+ const debug = isDebug(program.opts().debug);
268
+ logger.default.VERBOSE = isVerbose(verbose);
265
269
  let branch, authDir, savedDir, launchArgs;
266
270
  let isSteam;
267
271
  if (index.find(".")) workDir = ".";
@@ -328,7 +332,7 @@ program.command("auth").option("-g, --global", "Remove global auth files").optio
328
332
  if (!isSteam) {
329
333
  logger.default.warnp("Authenticating with", "non-steam launcher".yellow);
330
334
  }
331
- index$1.auth.prompt({
335
+ const success = await index$1.auth.prompt({
332
336
  email,
333
337
  password,
334
338
  debug,
@@ -337,6 +341,7 @@ program.command("auth").option("-g, --global", "Remove global auth files").optio
337
341
  savedDir,
338
342
  launchArgs
339
343
  });
344
+ if (!success) process.exit(1);
340
345
  }
341
346
  );
342
347
  program.command("info").alias("n").description(
@@ -357,8 +362,9 @@ program.command("install <pluginUrl...>").alias("i").option("-f, --force", "Forc
357
362
  );
358
363
  process.exit(1);
359
364
  }
360
- const { verbose, force } = program.opts();
361
- logger.default.VERBOSE = Boolean(verbose);
365
+ const { force } = program.opts();
366
+ const verbose = isVerbose(program.opts().verbose);
367
+ logger.default.VERBOSE = verbose;
362
368
  index$1.pluginUtil.install(plugins, { verbose, force });
363
369
  });
364
370
  program.command("update [pluginNames...]").alias("u").option("-f, --force", "Forcefully re-upgrade existing plugin").option("-v, --verbose", "Print extra messages for debugging purposes").description("Updates all or selected installed plugins to latest versions").action(async (plugins) => {
@@ -370,8 +376,9 @@ program.command("update [pluginNames...]").alias("u").option("-f, --force", "For
370
376
  );
371
377
  process.exit(1);
372
378
  }
373
- const { verbose, force } = program.opts();
374
- logger.default.VERBOSE = Boolean(verbose);
379
+ const { force } = program.opts();
380
+ const verbose = isVerbose(program.opts().verbose);
381
+ logger.default.VERBOSE = verbose;
375
382
  index$1.pluginUtil.update(plugins, { verbose, force });
376
383
  });
377
384
  program.command("check [pluginNames...]").option("-v, --verbose", "Print extra messages for debugging purposes").description("Checks plugins for compatibility issues").action(async (plugins) => {
@@ -383,18 +390,18 @@ program.command("check [pluginNames...]").option("-v, --verbose", "Print extra m
383
390
  );
384
391
  process.exit(1);
385
392
  }
386
- const { verbose } = program.opts();
387
- logger.default.VERBOSE = Boolean(verbose);
393
+ const verbose = isVerbose(program.opts().verbose);
394
+ logger.default.VERBOSE = verbose;
388
395
  index$1.pluginUtil.check(plugins, { verbose });
389
396
  });
390
397
  program.command("init-plugin").option("-v, --verbose", "Print extra messages for debugging purposes").description("Initializes a new plugin with the given name and settings").action(async () => {
391
398
  const { verbose } = program.opts();
392
- logger.default.VERBOSE = Boolean(verbose);
399
+ logger.default.VERBOSE = isVerbose(verbose);
393
400
  index$1.pluginUtil.init();
394
401
  });
395
402
  program.command("plugin-init").description("Alias for " + "init-plugin".yellow.underline).option("-v, --verbose", "Print extra messages for debugging purposes").action(async () => {
396
403
  const { verbose } = program.opts();
397
- logger.default.VERBOSE = Boolean(verbose);
404
+ logger.default.VERBOSE = isVerbose(verbose);
398
405
  index$1.pluginUtil.init();
399
406
  });
400
407
  program.command("get-config <pluginName> [configName]").option("-v, --verbose", "Print extra messages for debugging purposes").option("-j, --json", "Print config as json").description(
@@ -410,7 +417,7 @@ program.command("get-config <pluginName> [configName]").option("-v, --verbose",
410
417
  }
411
418
  const { verbose } = program.opts();
412
419
  const json = program.args.includes("-j") || program.args.includes("--json");
413
- logger.default.VERBOSE = Boolean(verbose);
420
+ logger.default.VERBOSE = isVerbose(verbose);
414
421
  if (!configName) {
415
422
  index$1.pluginUtil.listConfig(pluginName, json);
416
423
  } else {
@@ -430,7 +437,7 @@ program.command("set-config <pluginName> [configName] [configValue]").option("-y
430
437
  }
431
438
  const { verbose } = program.opts();
432
439
  const yes = program.args.includes("-y") || program.args.includes("--yes");
433
- logger.default.VERBOSE = Boolean(verbose);
440
+ logger.default.VERBOSE = isVerbose(verbose);
434
441
  if (!configName) {
435
442
  index$1.pluginUtil.resetAllConfigs(pluginName, yes);
436
443
  } else if (!configValue) {
@@ -464,7 +471,16 @@ async function setupSteam(config2, forceUpdate = false) {
464
471
  if (!fs.existsSync(softconfig.STEAMCMD_PATH)) {
465
472
  const hasSteamcmd = hasbin.sync("steamcmd");
466
473
  if (!hasSteamcmd) {
467
- const { install } = process.env.SKIP_STEAMCMD_PROMPT === "true" ? { install: true } : await prompts({
474
+ const skipPrompt = env.parseEnvBool("SKIP_STEAMCMD_PROMPT") === true;
475
+ if (!skipPrompt && env.isNonInteractive()) {
476
+ logger.default.errorp(
477
+ "SteamCMD is not installed and there is no terminal to prompt on. Set",
478
+ "SKIP_STEAMCMD_PROMPT=true".yellow,
479
+ "to install it without asking. Exiting..."
480
+ );
481
+ process.exit(1);
482
+ }
483
+ const { install } = skipPrompt ? { install: true } : await prompts({
468
484
  type: "confirm",
469
485
  name: "install",
470
486
  message: "SteamCMD is not installed. OK to download it?",
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sources":["../src/main.ts"],"sourcesContent":["import soft, {\n getOverrideGameBinary,\n getSteamGameDir,\n getSteamInstallDir,\n} from '@/softconfig';\nimport { installLauncher } from '@cli/installer';\nimport * as config from '@config';\nimport { readBinaryVersion } from '@omegga/matchers/version';\nimport Omegga from '@omegga/server';\nimport * as file from '@util/file';\nimport { isContainer } from '@util/container';\nimport 'colors';\nimport commander from 'commander';\nimport dotenv from 'dotenv';\nimport hasbin from 'hasbin';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport prompts from 'prompts';\nimport updateNotifier from 'update-notifier-cjs';\nimport { auth, config as omeggaConfig, pluginUtil, Terminal } from './cli';\nimport { IConfig } from './config/types';\nimport Logger from './logger';\nimport { GAME_BIN_PATH, STEAMCMD_PATH } from './softconfig';\nimport {\n hasSteamUpdate,\n steamcmdDownloadGame,\n steamcmdDownloadSelf,\n steamcmdInteractiveLogin,\n} from './updater';\nimport { PKG, VERSION } from './version';\n\ndotenv.config({ quiet: true });\n\nconst notifier =\n process.env.PACKAGE_NOTIFIER !== 'false'\n ? updateNotifier({\n pkg: PKG,\n updateCheckInterval: 1000 * 60 * 60 * 24,\n })\n : null;\nif (notifier) {\n const { update } = notifier;\n notifier.notify(\n update && isContainer()\n ? {\n message: `Update available ${update.current} → ${update.latest}\\nPull a new container image to update`,\n }\n : undefined,\n );\n}\n\n// TODO: let omegga bundle config (roles, bans, server config) to zip\n// TODO: let omegga unbundle config from zip to current omegga dir\n\n// write a default config file\nconst createDefaultConfig = () => {\n Logger.logp('Created default config file');\n config.write(soft.CONFIG_FILENAMES[0] + '.yml', config.defaultConfig);\n file.mkdir(`data/${soft.CONFIG_SAVED_DIR}/Builds`);\n file.mkdir('plugins');\n return config.defaultConfig;\n};\n\nconst program = commander\n .description(PKG.description)\n .version(VERSION)\n .option(\n '-d, --debug',\n 'Print all console logs rather than just chat messages (env: BRICKADIA_DEBUG)',\n )\n .option(\n '-u, --update',\n 'Check for brickadia updates (on steam) and install them if available',\n )\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .action(async () => {\n const { verbose, update } = program.opts();\n // BRICKADIA_DEBUG is an env-var alias for the --debug flag\n const debug = Boolean(program.opts().debug || process.env.BRICKADIA_DEBUG);\n if (program.args.length > 0) {\n program.help();\n process.exit(1);\n }\n Logger.VERBOSE = Boolean(verbose);\n\n // default working directory is the one specified in config\n let workDir = config.store.get('defaultOmegga');\n Logger.verbose('Using working directory', workDir?.yellow);\n\n // if there's a config in the current directory, use that one instead\n if (config.find('.')) workDir = '.';\n\n // check if configured path exists\n if (!fs.existsSync(workDir)) {\n Logger.errorp('configured omegga default path does not exist');\n process.exit(1);\n }\n if (!fs.statSync(workDir).isDirectory()) {\n Logger.errorp('configured omegga default path is not a directory');\n process.exit(1);\n }\n\n // find the config for the working directory\n const configFile = config.find(workDir);\n Logger.verbose('Target config file:', configFile?.yellow);\n let conf: IConfig;\n\n // create a default config file if it does not already exist, otherwise load in the existing one\n if (!configFile) {\n Logger.verbose('Creating a new config');\n conf = createDefaultConfig();\n } else {\n Logger.verbose('Reading config file');\n try {\n conf = config.read(configFile);\n } catch (error) {\n Logger.errorp('Error reading config file');\n Logger.verbose(error);\n // starting without a working config would only crash later\n process.exit(1);\n }\n }\n\n config.applyPortOverrides(conf);\n config.applyMetricsOverrides(conf);\n\n if (conf?.terminal?.timestamp) {\n Logger.setTimestamp(conf.terminal.timestamp);\n }\n\n const overrideBinary = getOverrideGameBinary();\n const isSteam = !conf?.server?.branch;\n if (overrideBinary) {\n if (!fs.existsSync(overrideBinary)) {\n Logger.error(\n 'Binary',\n overrideBinary.yellow,\n 'in',\n 'BRICKADIA_DIR'.yellow,\n 'does not exist!',\n );\n process.exit(1);\n }\n\n Logger.verbose(\n 'Using override binary',\n overrideBinary.yellow,\n '- skipping download.',\n );\n } else if (isSteam) {\n conf.__STEAM = true;\n await setupSteam(conf, update);\n } else {\n Logger.warnp(\n 'Brickadia will be launched with',\n 'non-steam launcher'.yellow,\n );\n Logger.warnp(\n 'New versions of Brickadia are not published on the old launcher.'\n .yellow,\n );\n\n // Check if the local launcher is installed\n if (fs.existsSync(soft.LOCAL_LAUNCHER)) {\n Logger.verbose(\"Using omegga's brickadia-launcher\");\n conf.server.__LOCAL = true;\n } else {\n Logger.verbose(\"Installing launcher as it's missing\");\n await installLauncher();\n }\n }\n\n const globalToken = auth.getGlobalToken();\n\n const hasHostingToken = Boolean(\n conf?.credentials?.token || process.env.BRICKADIA_TOKEN || globalToken,\n );\n\n // Skip auth when the hosting token is present\n if (hasHostingToken) {\n Logger.verbose(\n 'Skipping auth token generation due to host token presence',\n );\n if (conf?.credentials?.token)\n Logger.verbose('Found token in config file');\n else if (process.env.BRICKADIA_TOKEN)\n Logger.verbose('Found token in', 'BRICKADIA_TOKEN'.yellow);\n else if (globalToken)\n Logger.verbose('Found token in omegga global config');\n else Logger.verbose('unreachable - no token found');\n\n // check if the auth files don't exist\n } else if (\n !auth.exists(\n path.join(\n workDir,\n soft.DATA_PATH,\n conf?.server?.savedDir ?? soft.CONFIG_SAVED_DIR,\n conf?.server?.authDir ?? soft.CONFIG_AUTH_DIR,\n ),\n )\n ) {\n const success = await auth.prompt({\n debug,\n email: conf?.credentials?.['email'] ?? process.env.BRICKADIA_USER,\n password: conf?.credentials?.['password'] ?? process.env.BRICKADIA_PASS,\n isSteam,\n branch: conf?.server?.branch,\n authDir: conf?.server?.authDir,\n savedDir: conf?.server?.savedDir,\n launchArgs: conf?.server?.launchArgs,\n });\n if (!success) {\n Logger.errorp('Start aborted - could not generate auth tokens');\n process.exit(1);\n }\n } else {\n Logger.verbose(\n 'Skipping auth token generation due to existing auth files',\n );\n }\n\n // build options\n const options = {\n // default enable web ui (set to false)\n noweb: typeof conf.omegga?.webui === 'boolean' && !conf.omegga?.webui,\n // default enable https (set to true, will not be https if it can't generate)\n https: typeof conf.omegga?.https !== 'boolean' || conf.omegga?.https,\n port: conf.omegga?.port || soft.DEFAULT_PORT,\n debug,\n };\n\n Logger.verbose('Launching with options', options);\n\n // setup the server\n const server = new Omegga(workDir, conf, options);\n Logger.verbose('Created omegga object');\n\n if (verbose) {\n server.on(\n '*',\n (ev: string) => ev !== 'line' && Logger.verbose('EVENT'.green, ev),\n );\n }\n\n // create a terminal\n Logger.setTerminal(new Terminal(server, options));\n\n if (notifier?.update) {\n Logger.logp(\n `Omegga update is available (${('v' + notifier.update.latest).yellow})!`,\n isContainer()\n ? 'Pull a new container image to update!'\n : `Run ${'npm i -g omegga'.yellow} to update!`,\n );\n }\n\n if (\n conf.__STEAM &&\n !update &&\n !conf.server?.steambetaPassword &&\n process.env.STEAM_NOTIFIER !== 'false'\n ) {\n hasSteamUpdate(conf.server?.steambeta).then(hasUpdate => {\n if (hasUpdate) {\n Logger.logp('A server update is available!'.brightBlue);\n Logger.log(\n ' Restart with',\n 'omegga --update'.yellow,\n 'to update every start.',\n );\n Logger.log(' Run', '/update'.yellow, 'to update', 'now'.green + '!');\n } else {\n Logger.verbose('No server updates available.');\n }\n });\n }\n\n // resolved from the binary, so it's available before the server starts\n const gameVersion = readBinaryVersion(server.getGameBinaryPath());\n\n Logger.logp(\n `Launching Brickadia Server${\n gameVersion ? ' ' + ('CL' + gameVersion).green : ''\n } on port ${('' + (conf.server.port || 7777)).green}...`,\n );\n\n // start the server\n Logger.verbose('Starting Omegga');\n server.start();\n });\n\nprogram\n .command('init')\n .description('Sets up the current directory as a brickadia server')\n .action(async () => {\n const configFile = config.find('.');\n if (configFile) {\n Logger.errorp('Config file already exists:', configFile.yellow.underline);\n process.exit(1);\n }\n createDefaultConfig();\n });\n\nprogram\n .command('steamlogin')\n .description('Interactively log in to Steam (for Steam Guard authentication)')\n .action(async () => {\n if (!process.env.STEAM_USERNAME) {\n Logger.errorp('STEAM_USERNAME environment variable is required.');\n Logger.errorp('Set it in your .env file or environment.');\n process.exit(1);\n }\n\n if (!fs.existsSync(STEAMCMD_PATH)) {\n Logger.errorp(\n 'SteamCMD is not installed. Run',\n 'omegga'.yellow,\n 'first to set it up.',\n );\n process.exit(1);\n }\n\n Logger.logp('Logging in to Steam interactively...');\n const success = await steamcmdInteractiveLogin();\n if (success) {\n Logger.logp('Steam login successful. Credentials are now cached.');\n } else {\n Logger.errorp('Steam login failed.');\n process.exit(1);\n }\n });\n\nprogram\n .command('config [field] [value]')\n .description(\n \"Configure Omegga's default behavior.\\n\" +\n 'Type ' +\n 'omegga config list'.yellow.underline +\n ' for current settings and available fields',\n )\n .action((field, value) => {\n if (!field) field = 'list';\n omeggaConfig(field, value, program.opts());\n });\n\nprogram\n .command('auth')\n .option('-g, --global', 'Remove global auth files')\n .option('-l, --local', 'Remove local auth files')\n .option('-w, --workdir', 'Remove configured location auth files')\n .option('-u, --email <email>', 'User email (must provide password)')\n .option('-p, --pass <password>', 'User password (must provide email)')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description(\n 'Generates server auth tokens from brickadia account email+password',\n )\n .action(\n async ({\n email,\n pass: password,\n local: localAuth,\n workDir,\n global: globalAuth,\n }) => {\n const { verbose } = program.opts();\n // BRICKADIA_DEBUG is an env-var alias for the --debug flag\n const debug = Boolean(\n program.opts().debug || process.env.BRICKADIA_DEBUG,\n );\n Logger.VERBOSE = Boolean(verbose);\n\n let branch: string | undefined,\n authDir: string | undefined,\n savedDir: string | undefined,\n launchArgs: string | undefined;\n let isSteam: boolean | undefined;\n\n // if there's a config in the current directory, use that one instead\n if (config.find('.')) workDir = '.';\n\n // check if configured path exists\n if (fs.existsSync(workDir) && fs.statSync(workDir).isDirectory()) {\n Logger.verbose('Using working directory', workDir.yellow);\n // find the config for the working directory\n const configFile = config.find(workDir);\n Logger.verbose('Target config file:', configFile?.yellow);\n if (configFile) {\n try {\n // read the config and extract the branch\n const conf = config.read(configFile);\n Logger.verbose(\n 'Auth config:',\n conf?.server ?? 'no server config'.grey,\n );\n branch = conf?.server?.branch;\n authDir = conf?.server?.authDir;\n savedDir = conf?.server?.savedDir;\n launchArgs = conf?.server?.launchArgs;\n isSteam = !conf?.server?.branch;\n\n if (localAuth && conf?.credentials?.token) {\n Logger.logp(\n \"This server's auth is managed by the token in\",\n configFile.yellow,\n );\n return;\n }\n } catch (error) {\n Logger.errorp('Error reading config file');\n Logger.verbose(error);\n }\n }\n } else {\n Logger.verbose('Using default working directory', workDir.yellow);\n }\n\n savedDir ??= soft.CONFIG_SAVED_DIR;\n\n const workdirPath = path.join(\n config.store.get('defaultOmegga'),\n `data/${savedDir}/Auth`,\n );\n\n if (globalAuth || localAuth) {\n if (globalAuth) {\n const globalAuthPath = path.join(\n soft.CONFIG_HOME,\n savedDir !== soft.CONFIG_SAVED_DIR ? savedDir : '',\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n Logger.logp('Clearing auth files from', globalAuthPath.yellow);\n auth.clean(globalAuthPath);\n }\n if (workDir) {\n Logger.logp('Clearing auth files from', workdirPath.yellow);\n await file.rmdir(workdirPath);\n }\n if (localAuth) {\n const localPath = path.resolve(\n `data/${savedDir}/`,\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n Logger.logp('Clearing auth files from', localPath.yellow);\n await file.rmdir(localPath);\n }\n return;\n }\n\n if (!isSteam) {\n Logger.warnp('Authenticating with', 'non-steam launcher'.yellow);\n }\n\n auth.prompt({\n email,\n password,\n debug,\n branch,\n authDir,\n savedDir,\n launchArgs,\n });\n },\n );\n\nprogram\n .command('info')\n .alias('n')\n .description(\n 'Shows server name, description, port, install info, and installed plugins',\n )\n .action(async () => {\n Logger.errorp('not implemented yet');\n // TODO: implement config parsing\n });\n\nprogram\n .command('install <pluginUrl...>')\n .alias('i')\n .option('-f, --force', 'Forcefully re-install existing plugin') // TODO: implement install --force\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Installs a plugin to the current brickadia server')\n .action(async plugins => {\n if (!hasbin.sync('git')) {\n Logger.errorp('git'.yellow, 'must be installed to install plugins.');\n process.exit(1);\n }\n\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose, force } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n pluginUtil.install(plugins, { verbose, force });\n });\n\nprogram\n .command('update [pluginNames...]')\n .alias('u')\n .option('-f, --force', 'Forcefully re-upgrade existing plugin') // TODO: implement update --force\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Updates all or selected installed plugins to latest versions')\n .action(async plugins => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose, force } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n pluginUtil.update(plugins, { verbose, force });\n });\n\nprogram\n .command('check [pluginNames...]')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Checks plugins for compatibility issues')\n .action(async plugins => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n pluginUtil.check(plugins, { verbose });\n });\n\nprogram\n .command('init-plugin')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Initializes a new plugin with the given name and settings')\n .action(async () => {\n const { verbose } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n\n pluginUtil.init();\n });\n\nprogram\n .command('plugin-init')\n .description('Alias for ' + 'init-plugin'.yellow.underline)\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .action(async () => {\n const { verbose } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n\n pluginUtil.init();\n });\n\nprogram\n .command('get-config <pluginName> [configName]')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .option('-j, --json', 'Print config as json')\n .description(\n 'Gets a config for a plugin. If ' +\n 'configName'.yellow.underline +\n ' is omitted, returns all config values.',\n )\n .action(async (pluginName, configName) => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n const json = program.args.includes('-j') || program.args.includes('--json');\n Logger.VERBOSE = Boolean(verbose);\n if (!configName) {\n pluginUtil.listConfig(pluginName, json);\n } else {\n pluginUtil.getConfig(pluginName, configName, json);\n }\n });\n\nprogram\n .command('set-config <pluginName> [configName] [configValue]')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description(\n 'Sets a config for a plugin. If ' +\n 'configValue'.yellow.underline +\n ' is omitted, the config will be reset. If ' +\n 'configName'.yellow.underline +\n ' is omitted, the entire plugin config will be reset.',\n )\n .action(async (pluginName, configName, configValue) => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n const yes = program.args.includes('-y') || program.args.includes('--yes');\n Logger.VERBOSE = Boolean(verbose);\n if (!configName) {\n pluginUtil.resetAllConfigs(pluginName, yes);\n } else if (!configValue) {\n pluginUtil.resetConfig(pluginName, configName);\n } else {\n pluginUtil.setConfig(pluginName, configName, configValue);\n }\n });\n\nprogram.parseAsync(process.argv);\n\nasync function setupSteam(config: config.IConfig, forceUpdate = false) {\n const steambeta = config?.server?.steambeta;\n const steambetaPassword = config?.server?.steambetaPassword;\n\n const binaryPath = path.join(\n getSteamInstallDir(), // steam install directory\n steambeta ?? 'main', // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n\n if (!forceUpdate && fs.existsSync(binaryPath)) {\n Logger.verbose(\n 'Game binary already exists at',\n binaryPath.yellow,\n '- skipping download.',\n );\n return;\n }\n\n // Check if steamcmd is installed\n if (!fs.existsSync(STEAMCMD_PATH)) {\n // Lookup steamcmd in path\n const hasSteamcmd = hasbin.sync('steamcmd');\n\n if (!hasSteamcmd) {\n // Prompt to install steamcmd\n const { install } =\n process.env.SKIP_STEAMCMD_PROMPT === 'true'\n ? { install: true }\n : await prompts({\n type: 'confirm',\n name: 'install',\n message: 'SteamCMD is not installed. OK to download it?',\n initial: true,\n });\n\n if (!install) {\n Logger.errorp('SteamCMD is required for steam support. Exiting...');\n process.exit(1);\n }\n\n Logger.logp('Downloading SteamCMD...');\n }\n\n try {\n steamcmdDownloadSelf();\n if (!fs.existsSync(STEAMCMD_PATH)) {\n Logger.errorp('Failed to setup SteamCMD. Exiting...');\n process.exit(1);\n }\n } catch (err) {\n Logger.errorp('Error setting up SteamCMD:', err);\n process.exit(1);\n }\n }\n\n Logger.logp('Downloading Brickadia', (steambeta ?? 'main').yellow, '...');\n try {\n await steamcmdDownloadGame({ steambeta, steambetaPassword });\n } catch (err) {\n Logger.errorp('Error downloading Brickadia:', err);\n process.exit(1);\n }\n}\n"],"names":["PKG","isContainer","Logger","config.write","soft","config.defaultConfig","file.mkdir","VERSION","config.store","config.find","config.read","config.applyPortOverrides","config.applyMetricsOverrides","getOverrideGameBinary","installLauncher","auth","server","Omegga","Terminal","hasSteamUpdate","readBinaryVersion","STEAMCMD_PATH","steamcmdInteractiveLogin","omeggaConfig","file.rmdir","pluginUtil","config","getSteamInstallDir","getSteamGameDir","GAME_BIN_PATH","steamcmdDownloadSelf","steamcmdDownloadGame"],"mappings":"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"}
1
+ {"version":3,"file":"main.js","sources":["../src/main.ts"],"sourcesContent":["import soft, {\n getOverrideGameBinary,\n getSteamGameDir,\n getSteamInstallDir,\n} from '@/softconfig';\nimport { installLauncher } from '@cli/installer';\nimport * as config from '@config';\nimport { readBinaryVersion } from '@omegga/matchers/version';\nimport Omegga from '@omegga/server';\nimport * as file from '@util/file';\nimport { isContainer } from '@util/container';\nimport { isNonInteractive, parseEnvBool } from '@util/env';\nimport 'colors';\nimport commander from 'commander';\nimport dotenv from 'dotenv';\nimport hasbin from 'hasbin';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport prompts from 'prompts';\nimport updateNotifier from 'update-notifier-cjs';\nimport { auth, config as omeggaConfig, pluginUtil, Terminal } from './cli';\nimport { IConfig } from './config/types';\nimport Logger from './logger';\nimport { GAME_BIN_PATH, STEAMCMD_PATH } from './softconfig';\nimport {\n hasSteamUpdate,\n steamcmdDownloadGame,\n steamcmdDownloadSelf,\n steamcmdInteractiveLogin,\n} from './updater';\nimport { PKG, VERSION } from './version';\n\ndotenv.config({ quiet: true });\n\nconst notifier =\n process.env.PACKAGE_NOTIFIER !== 'false'\n ? updateNotifier({\n pkg: PKG,\n updateCheckInterval: 1000 * 60 * 60 * 24,\n })\n : null;\nif (notifier) {\n const { update } = notifier;\n notifier.notify(\n update && isContainer()\n ? {\n message: `Update available ${update.current} → ${update.latest}\\nPull a new container image to update`,\n }\n : undefined,\n );\n}\n\n// TODO: let omegga bundle config (roles, bans, server config) to zip\n// TODO: let omegga unbundle config from zip to current omegga dir\n\n// write a default config file\nconst createDefaultConfig = () => {\n Logger.logp('Created default config file');\n config.write(soft.CONFIG_FILENAMES[0] + '.yml', config.defaultConfig);\n file.mkdir(`data/${soft.CONFIG_SAVED_DIR}/Builds`);\n file.mkdir('plugins');\n return config.defaultConfig;\n};\n\n/**\n * `--verbose` and `--debug` also have environment aliases. Both parse the\n * value rather than testing for presence: an orchestrator that materialises\n * every declared variable has no way to leave one unset, so `VERBOSE=false`\n * has to mean false.\n */\nconst isVerbose = (flag?: unknown) =>\n Boolean(flag) || parseEnvBool('VERBOSE') === true;\nconst isDebug = (flag?: unknown) =>\n Boolean(flag) || parseEnvBool('BRICKADIA_DEBUG') === true;\n\nconst program = commander\n .description(PKG.description)\n .version(VERSION)\n .option(\n '-d, --debug',\n 'Print all console logs rather than just chat messages (env: BRICKADIA_DEBUG)',\n )\n .option(\n '-u, --update',\n 'Check for brickadia updates (on steam) and install them if available',\n )\n .option(\n '-v, --verbose',\n 'Print extra messages for debugging purposes (env: VERBOSE)',\n )\n .action(async () => {\n const { verbose, update } = program.opts();\n const debug = isDebug(program.opts().debug);\n if (program.args.length > 0) {\n program.help();\n process.exit(1);\n }\n Logger.VERBOSE = isVerbose(verbose);\n\n // default working directory is the one specified in config\n let workDir = config.store.get('defaultOmegga');\n Logger.verbose('Using working directory', workDir?.yellow);\n\n // if there's a config in the current directory, use that one instead\n if (config.find('.')) workDir = '.';\n\n // check if configured path exists\n if (!fs.existsSync(workDir)) {\n Logger.errorp('configured omegga default path does not exist');\n process.exit(1);\n }\n if (!fs.statSync(workDir).isDirectory()) {\n Logger.errorp('configured omegga default path is not a directory');\n process.exit(1);\n }\n\n // find the config for the working directory\n const configFile = config.find(workDir);\n Logger.verbose('Target config file:', configFile?.yellow);\n let conf: IConfig;\n\n // create a default config file if it does not already exist, otherwise load in the existing one\n if (!configFile) {\n Logger.verbose('Creating a new config');\n conf = createDefaultConfig();\n } else {\n Logger.verbose('Reading config file');\n try {\n conf = config.read(configFile);\n } catch (error) {\n Logger.errorp('Error reading config file');\n Logger.verbose(error);\n // starting without a working config would only crash later\n process.exit(1);\n }\n }\n\n config.applyPortOverrides(conf);\n config.applyMetricsOverrides(conf);\n\n if (conf?.terminal?.timestamp) {\n Logger.setTimestamp(conf.terminal.timestamp);\n }\n\n const overrideBinary = getOverrideGameBinary();\n const isSteam = !conf?.server?.branch;\n if (overrideBinary) {\n if (!fs.existsSync(overrideBinary)) {\n Logger.error(\n 'Binary',\n overrideBinary.yellow,\n 'in',\n 'BRICKADIA_DIR'.yellow,\n 'does not exist!',\n );\n process.exit(1);\n }\n\n Logger.verbose(\n 'Using override binary',\n overrideBinary.yellow,\n '- skipping download.',\n );\n } else if (isSteam) {\n conf.__STEAM = true;\n await setupSteam(conf, update);\n } else {\n Logger.warnp(\n 'Brickadia will be launched with',\n 'non-steam launcher'.yellow,\n );\n Logger.warnp(\n 'New versions of Brickadia are not published on the old launcher.'\n .yellow,\n );\n\n // Check if the local launcher is installed\n if (fs.existsSync(soft.LOCAL_LAUNCHER)) {\n Logger.verbose(\"Using omegga's brickadia-launcher\");\n conf.server.__LOCAL = true;\n } else {\n Logger.verbose(\"Installing launcher as it's missing\");\n await installLauncher();\n }\n }\n\n const globalToken = auth.getGlobalToken();\n\n const hasHostingToken = Boolean(\n conf?.credentials?.token || process.env.BRICKADIA_TOKEN || globalToken,\n );\n\n // Skip auth when the hosting token is present\n if (hasHostingToken) {\n Logger.verbose(\n 'Skipping auth token generation due to host token presence',\n );\n if (conf?.credentials?.token)\n Logger.verbose('Found token in config file');\n else if (process.env.BRICKADIA_TOKEN)\n Logger.verbose('Found token in', 'BRICKADIA_TOKEN'.yellow);\n else if (globalToken)\n Logger.verbose('Found token in omegga global config');\n else Logger.verbose('unreachable - no token found');\n\n // check if the auth files don't exist\n } else if (\n !auth.exists(\n path.join(\n workDir,\n soft.DATA_PATH,\n conf?.server?.savedDir ?? soft.CONFIG_SAVED_DIR,\n conf?.server?.authDir ?? soft.CONFIG_AUTH_DIR,\n ),\n )\n ) {\n const success = await auth.prompt({\n debug,\n email: conf?.credentials?.['email'] ?? process.env.BRICKADIA_USER,\n password: conf?.credentials?.['password'] ?? process.env.BRICKADIA_PASS,\n isSteam,\n branch: conf?.server?.branch,\n authDir: conf?.server?.authDir,\n savedDir: conf?.server?.savedDir,\n launchArgs: conf?.server?.launchArgs,\n });\n if (!success) {\n Logger.errorp('Start aborted - could not generate auth tokens');\n process.exit(1);\n }\n } else {\n Logger.verbose(\n 'Skipping auth token generation due to existing auth files',\n );\n }\n\n // build options\n const options = {\n // default enable web ui (set to false)\n noweb: typeof conf.omegga?.webui === 'boolean' && !conf.omegga?.webui,\n // default enable https (set to true, will not be https if it can't generate)\n https: typeof conf.omegga?.https !== 'boolean' || conf.omegga?.https,\n port: conf.omegga?.port || soft.DEFAULT_PORT,\n debug,\n };\n\n Logger.verbose('Launching with options', options);\n\n // setup the server\n const server = new Omegga(workDir, conf, options);\n Logger.verbose('Created omegga object');\n\n if (verbose) {\n server.on(\n '*',\n (ev: string) => ev !== 'line' && Logger.verbose('EVENT'.green, ev),\n );\n }\n\n // create a terminal\n Logger.setTerminal(new Terminal(server, options));\n\n if (notifier?.update) {\n Logger.logp(\n `Omegga update is available (${('v' + notifier.update.latest).yellow})!`,\n isContainer()\n ? 'Pull a new container image to update!'\n : `Run ${'npm i -g omegga'.yellow} to update!`,\n );\n }\n\n if (\n conf.__STEAM &&\n !update &&\n !conf.server?.steambetaPassword &&\n process.env.STEAM_NOTIFIER !== 'false'\n ) {\n hasSteamUpdate(conf.server?.steambeta).then(hasUpdate => {\n if (hasUpdate) {\n Logger.logp('A server update is available!'.brightBlue);\n Logger.log(\n ' Restart with',\n 'omegga --update'.yellow,\n 'to update every start.',\n );\n Logger.log(' Run', '/update'.yellow, 'to update', 'now'.green + '!');\n } else {\n Logger.verbose('No server updates available.');\n }\n });\n }\n\n // resolved from the binary, so it's available before the server starts\n const gameVersion = readBinaryVersion(server.getGameBinaryPath());\n\n Logger.logp(\n `Launching Brickadia Server${\n gameVersion ? ' ' + ('CL' + gameVersion).green : ''\n } on port ${('' + (conf.server.port || 7777)).green}...`,\n );\n\n // start the server\n Logger.verbose('Starting Omegga');\n server.start();\n });\n\nprogram\n .command('init')\n .description('Sets up the current directory as a brickadia server')\n .action(async () => {\n const configFile = config.find('.');\n if (configFile) {\n Logger.errorp('Config file already exists:', configFile.yellow.underline);\n process.exit(1);\n }\n createDefaultConfig();\n });\n\nprogram\n .command('steamlogin')\n .description('Interactively log in to Steam (for Steam Guard authentication)')\n .action(async () => {\n if (!process.env.STEAM_USERNAME) {\n Logger.errorp('STEAM_USERNAME environment variable is required.');\n Logger.errorp('Set it in your .env file or environment.');\n process.exit(1);\n }\n\n if (!fs.existsSync(STEAMCMD_PATH)) {\n Logger.errorp(\n 'SteamCMD is not installed. Run',\n 'omegga'.yellow,\n 'first to set it up.',\n );\n process.exit(1);\n }\n\n Logger.logp('Logging in to Steam interactively...');\n const success = await steamcmdInteractiveLogin();\n if (success) {\n Logger.logp('Steam login successful. Credentials are now cached.');\n } else {\n Logger.errorp('Steam login failed.');\n process.exit(1);\n }\n });\n\nprogram\n .command('config [field] [value]')\n .description(\n \"Configure Omegga's default behavior.\\n\" +\n 'Type ' +\n 'omegga config list'.yellow.underline +\n ' for current settings and available fields',\n )\n .action((field, value) => {\n if (!field) field = 'list';\n omeggaConfig(field, value, program.opts());\n });\n\nprogram\n .command('auth')\n .option('-g, --global', 'Remove global auth files')\n .option('-l, --local', 'Remove local auth files')\n .option('-w, --workdir', 'Remove configured location auth files')\n .option('-u, --email <email>', 'User email (must provide password)')\n .option('-p, --pass <password>', 'User password (must provide email)')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description(\n 'Generates server auth tokens from brickadia account email+password',\n )\n .action(\n async ({\n email,\n pass: password,\n local: localAuth,\n workDir,\n global: globalAuth,\n }) => {\n const { verbose } = program.opts();\n const debug = isDebug(program.opts().debug);\n Logger.VERBOSE = isVerbose(verbose);\n\n let branch: string | undefined,\n authDir: string | undefined,\n savedDir: string | undefined,\n launchArgs: string | undefined;\n let isSteam: boolean | undefined;\n\n // if there's a config in the current directory, use that one instead\n if (config.find('.')) workDir = '.';\n\n // check if configured path exists\n if (fs.existsSync(workDir) && fs.statSync(workDir).isDirectory()) {\n Logger.verbose('Using working directory', workDir.yellow);\n // find the config for the working directory\n const configFile = config.find(workDir);\n Logger.verbose('Target config file:', configFile?.yellow);\n if (configFile) {\n try {\n // read the config and extract the branch\n const conf = config.read(configFile);\n Logger.verbose(\n 'Auth config:',\n conf?.server ?? 'no server config'.grey,\n );\n branch = conf?.server?.branch;\n authDir = conf?.server?.authDir;\n savedDir = conf?.server?.savedDir;\n launchArgs = conf?.server?.launchArgs;\n isSteam = !conf?.server?.branch;\n\n if (localAuth && conf?.credentials?.token) {\n Logger.logp(\n \"This server's auth is managed by the token in\",\n configFile.yellow,\n );\n return;\n }\n } catch (error) {\n Logger.errorp('Error reading config file');\n Logger.verbose(error);\n }\n }\n } else {\n Logger.verbose('Using default working directory', workDir.yellow);\n }\n\n savedDir ??= soft.CONFIG_SAVED_DIR;\n\n const workdirPath = path.join(\n config.store.get('defaultOmegga'),\n `data/${savedDir}/Auth`,\n );\n\n if (globalAuth || localAuth) {\n if (globalAuth) {\n const globalAuthPath = path.join(\n soft.CONFIG_HOME,\n savedDir !== soft.CONFIG_SAVED_DIR ? savedDir : '',\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n Logger.logp('Clearing auth files from', globalAuthPath.yellow);\n auth.clean(globalAuthPath);\n }\n if (workDir) {\n Logger.logp('Clearing auth files from', workdirPath.yellow);\n await file.rmdir(workdirPath);\n }\n if (localAuth) {\n const localPath = path.resolve(\n `data/${savedDir}/`,\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n Logger.logp('Clearing auth files from', localPath.yellow);\n await file.rmdir(localPath);\n }\n return;\n }\n\n if (!isSteam) {\n Logger.warnp('Authenticating with', 'non-steam launcher'.yellow);\n }\n\n const success = await auth.prompt({\n email,\n password,\n debug,\n branch,\n authDir,\n savedDir,\n launchArgs,\n });\n if (!success) process.exit(1);\n },\n );\n\nprogram\n .command('info')\n .alias('n')\n .description(\n 'Shows server name, description, port, install info, and installed plugins',\n )\n .action(async () => {\n Logger.errorp('not implemented yet');\n // TODO: implement config parsing\n });\n\nprogram\n .command('install <pluginUrl...>')\n .alias('i')\n .option('-f, --force', 'Forcefully re-install existing plugin') // TODO: implement install --force\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Installs a plugin to the current brickadia server')\n .action(async plugins => {\n if (!hasbin.sync('git')) {\n Logger.errorp('git'.yellow, 'must be installed to install plugins.');\n process.exit(1);\n }\n\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { force } = program.opts();\n const verbose = isVerbose(program.opts().verbose);\n Logger.VERBOSE = verbose;\n pluginUtil.install(plugins, { verbose, force });\n });\n\nprogram\n .command('update [pluginNames...]')\n .alias('u')\n .option('-f, --force', 'Forcefully re-upgrade existing plugin') // TODO: implement update --force\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Updates all or selected installed plugins to latest versions')\n .action(async plugins => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { force } = program.opts();\n const verbose = isVerbose(program.opts().verbose);\n Logger.VERBOSE = verbose;\n pluginUtil.update(plugins, { verbose, force });\n });\n\nprogram\n .command('check [pluginNames...]')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Checks plugins for compatibility issues')\n .action(async plugins => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const verbose = isVerbose(program.opts().verbose);\n Logger.VERBOSE = verbose;\n pluginUtil.check(plugins, { verbose });\n });\n\nprogram\n .command('init-plugin')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Initializes a new plugin with the given name and settings')\n .action(async () => {\n const { verbose } = program.opts();\n Logger.VERBOSE = isVerbose(verbose);\n\n pluginUtil.init();\n });\n\nprogram\n .command('plugin-init')\n .description('Alias for ' + 'init-plugin'.yellow.underline)\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .action(async () => {\n const { verbose } = program.opts();\n Logger.VERBOSE = isVerbose(verbose);\n\n pluginUtil.init();\n });\n\nprogram\n .command('get-config <pluginName> [configName]')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .option('-j, --json', 'Print config as json')\n .description(\n 'Gets a config for a plugin. If ' +\n 'configName'.yellow.underline +\n ' is omitted, returns all config values.',\n )\n .action(async (pluginName, configName) => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n const json = program.args.includes('-j') || program.args.includes('--json');\n Logger.VERBOSE = isVerbose(verbose);\n if (!configName) {\n pluginUtil.listConfig(pluginName, json);\n } else {\n pluginUtil.getConfig(pluginName, configName, json);\n }\n });\n\nprogram\n .command('set-config <pluginName> [configName] [configValue]')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description(\n 'Sets a config for a plugin. If ' +\n 'configValue'.yellow.underline +\n ' is omitted, the config will be reset. If ' +\n 'configName'.yellow.underline +\n ' is omitted, the entire plugin config will be reset.',\n )\n .action(async (pluginName, configName, configValue) => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n const yes = program.args.includes('-y') || program.args.includes('--yes');\n Logger.VERBOSE = isVerbose(verbose);\n if (!configName) {\n pluginUtil.resetAllConfigs(pluginName, yes);\n } else if (!configValue) {\n pluginUtil.resetConfig(pluginName, configName);\n } else {\n pluginUtil.setConfig(pluginName, configName, configValue);\n }\n });\n\nprogram.parseAsync(process.argv);\n\nasync function setupSteam(config: config.IConfig, forceUpdate = false) {\n const steambeta = config?.server?.steambeta;\n const steambetaPassword = config?.server?.steambetaPassword;\n\n const binaryPath = path.join(\n getSteamInstallDir(), // steam install directory\n steambeta ?? 'main', // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n\n if (!forceUpdate && fs.existsSync(binaryPath)) {\n Logger.verbose(\n 'Game binary already exists at',\n binaryPath.yellow,\n '- skipping download.',\n );\n return;\n }\n\n // Check if steamcmd is installed\n if (!fs.existsSync(STEAMCMD_PATH)) {\n // Lookup steamcmd in path\n const hasSteamcmd = hasbin.sync('steamcmd');\n\n if (!hasSteamcmd) {\n const skipPrompt = parseEnvBool('SKIP_STEAMCMD_PROMPT') === true;\n\n if (!skipPrompt && isNonInteractive()) {\n Logger.errorp(\n 'SteamCMD is not installed and there is no terminal to prompt on. Set',\n 'SKIP_STEAMCMD_PROMPT=true'.yellow,\n 'to install it without asking. Exiting...',\n );\n process.exit(1);\n }\n\n // Prompt to install steamcmd\n const { install } = skipPrompt\n ? { install: true }\n : await prompts({\n type: 'confirm',\n name: 'install',\n message: 'SteamCMD is not installed. OK to download it?',\n initial: true,\n });\n\n if (!install) {\n Logger.errorp('SteamCMD is required for steam support. Exiting...');\n process.exit(1);\n }\n\n Logger.logp('Downloading SteamCMD...');\n }\n\n try {\n steamcmdDownloadSelf();\n if (!fs.existsSync(STEAMCMD_PATH)) {\n Logger.errorp('Failed to setup SteamCMD. Exiting...');\n process.exit(1);\n }\n } catch (err) {\n Logger.errorp('Error setting up SteamCMD:', err);\n process.exit(1);\n }\n }\n\n Logger.logp('Downloading Brickadia', (steambeta ?? 'main').yellow, '...');\n try {\n await steamcmdDownloadGame({ steambeta, steambetaPassword });\n } catch (err) {\n Logger.errorp('Error downloading Brickadia:', err);\n process.exit(1);\n }\n}\n"],"names":["PKG","isContainer","Logger","config.write","soft","config.defaultConfig","file.mkdir","parseEnvBool","VERSION","config.store","config.find","config.read","config.applyPortOverrides","config.applyMetricsOverrides","getOverrideGameBinary","installLauncher","auth","server","Omegga","Terminal","hasSteamUpdate","readBinaryVersion","STEAMCMD_PATH","steamcmdInteractiveLogin","omeggaConfig","file.rmdir","pluginUtil","config","getSteamInstallDir","getSteamGameDir","GAME_BIN_PATH","isNonInteractive","steamcmdDownloadSelf","steamcmdDownloadGame"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const logger = require("../logger.js");
4
+ require("colors");
5
+ function parseEnvBool(name) {
6
+ const raw = process.env[name];
7
+ if (!raw) return void 0;
8
+ const value = raw.trim().toLowerCase();
9
+ if (["true", "1", "yes", "on"].includes(value)) return true;
10
+ if (["false", "0", "no", "off"].includes(value)) return false;
11
+ logger.default.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not a boolean`);
12
+ return void 0;
13
+ }
14
+ function isNonInteractive() {
15
+ return parseEnvBool("OMEGGA_NONINTERACTIVE") ?? !process.stdin.isTTY;
16
+ }
17
+ exports.isNonInteractive = isNonInteractive;
18
+ exports.parseEnvBool = parseEnvBool;
19
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sources":["../../src/util/env.ts"],"sourcesContent":["import Logger from '@/logger';\nimport 'colors';\n\n/** parse a boolean from the environment, warning (and ignoring) when it isn't one */\nexport function parseEnvBool(name: string) {\n const raw = process.env[name];\n if (!raw) return undefined;\n const value = raw.trim().toLowerCase();\n if (['true', '1', 'yes', 'on'].includes(value)) return true;\n if (['false', '0', 'no', 'off'].includes(value)) return false;\n Logger.warnp(`Ignoring ${name.yellow}: ${raw.yellow} is not a boolean`);\n return undefined;\n}\n\n/**\n * Whether omegga is allowed to block on an interactive prompt.\n *\n * Prompts are driven by raw key input, so anything that cannot deliver it\n * (a service manager with stdin on /dev/null, a panel console that submits\n * whole lines) waits at the prompt forever instead of failing. Callers that\n * would prompt should refuse instead when this is true.\n *\n * OMEGGA_NONINTERACTIVE overrides the guess in both directions: hosts that\n * allocate a real TTY but still cannot answer a prompt have to say so, and a\n * caller that really does feed stdin can set it to false.\n */\nexport function isNonInteractive(): boolean {\n return parseEnvBool('OMEGGA_NONINTERACTIVE') ?? !process.stdin.isTTY;\n}\n"],"names":["Logger"],"mappings":";;;;AAIO,SAAS,aAAa,MAAc;AACzC,QAAM,MAAM,QAAQ,IAAI,IAAI;AAC5B,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,QAAQ,IAAI,KAAA,EAAO,YAAA;AACzB,MAAI,CAAC,QAAQ,KAAK,OAAO,IAAI,EAAE,SAAS,KAAK,EAAG,QAAO;AACvD,MAAI,CAAC,SAAS,KAAK,MAAM,KAAK,EAAE,SAAS,KAAK,EAAG,QAAO;AACxDA,iBAAO,MAAM,YAAY,KAAK,MAAM,KAAK,IAAI,MAAM,mBAAmB;AACtE,SAAO;AACT;AAcO,SAAS,mBAA4B;AAC1C,SAAO,aAAa,uBAAuB,KAAK,CAAC,QAAQ,MAAM;AACjE;;;"}
package/docs/SUMMARY.md CHANGED
@@ -8,6 +8,7 @@
8
8
  - [Linux](install/linux.md)
9
9
  - [Windows (WSL)](install/wsl.md)
10
10
  - [Containers](containers.md)
11
+ - [Pterodactyl](guides/pterodactyl.md)
11
12
  - [Running](running.md)
12
13
  - [Configuration](config.md)
13
14
  - [Environment variables](env.md)
@@ -2,6 +2,11 @@
2
2
 
3
3
  Release tags publish an image to `ghcr.io/brickadia-community/omegga`.
4
4
 
5
+ To run that image under a Pterodactyl panel instead of directly, see
6
+ [Pterodactyl](guides/pterodactyl.md). Wings imposes its own user, working
7
+ directory, and console behaviour, and the egg in `docker/pterodactyl` handles
8
+ them.
9
+
5
10
  ```sh
6
11
  docker run -it --rm \
7
12
  -v omegga-home:/home/steam \
@@ -12,7 +17,7 @@ docker run -it --rm \
12
17
  ghcr.io/brickadia-community/omegga
13
18
  ```
14
19
 
15
- Generate a hosting token at https://brickadia.com/account/tokens; without one omegga stops at an interactive auth prompt on first start. Arguments are passed through, so `omegga --debug` and `bash` both work in place of the default command. Omegga handles `SIGINT` and `SIGTERM`, so ctrl+c and `docker stop` shut down gracefully - add `--init` if you also want zombie reaping.
20
+ Generate a hosting token at https://brickadia.com/account/tokens. Without one omegga falls back to an interactive auth prompt, which needs a tty: it stops there under `docker run -it`, and exits with the token URL when there is no tty to prompt on. Set `OMEGGA_NONINTERACTIVE=true` to get that same refusal on a host that does allocate a tty but cannot answer an arrow-key prompt. Arguments are passed through, so `omegga --debug` and `bash` both work in place of the default command. Omegga handles `SIGINT` and `SIGTERM`, so ctrl+c and `docker stop` shut down gracefully - add `--init` if you also want zombie reaping.
16
21
 
17
22
  Omegga is baked into the image, so it updates by pulling a new one rather than through npm:
18
23
 
package/docs/env.md CHANGED
@@ -18,8 +18,9 @@ These can be set in your shell or in a `.env` file the same directory as a `omeg
18
18
  - `STEAM_APP_ID` - Set the Steam App ID for Brickadia (default `3017590`)
19
19
  - `STEAM_USERNAME` - Set the Steam username for downloading Brickadia via steamcmd. Run `omegga steamlogin` to authenticate with Steam Guard
20
20
  - `STEAM_PASSWORD` - (Optional) Steam password; if not set, you will be prompted interactively
21
- - `VERBOSE` - Set to `true` to enable verbose logging (default `false`)
21
+ - `VERBOSE` - Set to `true` to enable verbose logging, equivalent to the `--verbose` flag (default `false`)
22
22
  - `PACKAGE_NOTIFIER` - When set to `false`, disables the npm update notifier
23
23
  - `STEAM_NOTIFIER` - When set to `false`, disables the SteamCMD update notifier
24
24
  - `SKIP_STEAMCMD_PROMPT` - When set to `true`, agrees to installing SteamCMD without prompting
25
- - `BRICKADIA_DEBUG` - When set, enables debug logging (equivalent to the `--debug` flag)
25
+ - `BRICKADIA_DEBUG` - Set to `true` to enable debug logging, equivalent to the `--debug` flag (default `false`)
26
+ - `OMEGGA_NONINTERACTIVE` - Set to `true` to fail instead of prompting for authentication. Defaults to `true` when stdin is not a terminal; set it explicitly on hosts that provide a terminal that cannot answer a prompt, such as a game panel console that only submits whole lines
@@ -0,0 +1,146 @@
1
+ # Pterodactyl
2
+
3
+ [Pterodactyl](https://pterodactyl.io/) runs game servers as Docker containers
4
+ managed by a web panel. An egg tells it how to install and run one.
5
+ [`docker/pterodactyl/egg-omegga.json`](https://github.com/brickadia-community/omegga/blob/master/docker/pterodactyl/egg-omegga.json)
6
+ in this repository is that egg for Omegga.
7
+
8
+ It runs the published image, so Omegga updates by changing the image tag rather
9
+ than reinstalling. Brickadia is not in the image; Omegga downloads it through
10
+ steamcmd on first start, into the server's own volume.
11
+
12
+ Setting one up takes three steps:
13
+
14
+ 1. [Import the egg](#importing-the-egg) into a nest.
15
+ 2. [Create a server](#creating-a-server) from it, with two allocations.
16
+ 3. [Set a hosting token](#the-hosting-token)
17
+
18
+ ## Importing the egg
19
+
20
+ The panel has no CLI or API for importing eggs, so this is a UI operation:
21
+
22
+ 1. Download the egg [here](https://raw.githubusercontent.com/brickadia-community/omegga/master/docker/pterodactyl/egg-omegga.json) or with `curl`:
23
+
24
+ ```sh
25
+ curl -LO https://raw.githubusercontent.com/brickadia-community/omegga/master/docker/pterodactyl/egg-omegga.json
26
+ ```
27
+
28
+ 2. **Admin > Nests > Import Egg**
29
+ 3. Upload `egg-omegga.json` and pick a nest (create a "Brickadia" nest if you
30
+ do not have one).
31
+
32
+ Both `PTDL_v1` and `PTDL_v2` are accepted by current panels; this egg is
33
+ `PTDL_v2`.
34
+
35
+ ## Creating a server
36
+
37
+ Omegga needs **two ports**, so the server needs two allocations:
38
+
39
+ | Allocation | Protocol | Used for |
40
+ |---|---|---|
41
+ | primary | UDP | Brickadia. `SERVER_PORT` drives `BRICKADIA_PORT` |
42
+ | second | TCP | the Omegga web UI. Set `OMEGGA_PORT` to this port |
43
+
44
+ Wings publishes each allocation on both TCP and UDP, so one allocation per
45
+ number is enough. They cannot share a number: Brickadia reports its configured
46
+ port to the master server, so the published port has to be the port it runs on.
47
+
48
+ Assign both on the server's **Network** tab, then set `OMEGGA_PORT` on the
49
+ **Startup** tab to the second one. The egg cannot do this for you: an egg
50
+ variable can hold a port number but cannot create the allocation.
51
+
52
+ Give the server at least 2-4 GB of disk for the Brickadia install, plus room
53
+ for worlds and plugins. The node has to be declared large enough in the panel
54
+ too, or the server cannot be placed on it.
55
+
56
+ ### The hosting token
57
+
58
+ `BRICKADIA_TOKEN` is required. Generate one at
59
+ <https://brickadia.com/account/tokens> and paste it into **Brickadia hosting
60
+ token** on the Startup tab.
61
+
62
+
63
+ Once authentication succeeds the token is stored in the volume
64
+ (`.config/omegga/global_auth_token`), so it survives restarts and reinstalls of
65
+ the container. The egg adds that path to the file denylist to keep it out of
66
+ the file manager.
67
+
68
+ ## Variables
69
+
70
+ | Variable | Default | Notes |
71
+ |---|---|---|
72
+ | `BRICKADIA_TOKEN` | none | Required. Hosting token from brickadia.com/account/tokens |
73
+ | `OMEGGA_PORT` | `8080` | Web UI port; must match a second allocation |
74
+ | `OMEGGA_FLAGS` | empty | Extra flags: `--update`, `--verbose`, `--debug` |
75
+ | `METRICS_ENABLED` | `false` | Prometheus endpoint; needs a third allocation |
76
+ | `METRICS_BIND` | `0.0.0.0` | Must be `0.0.0.0` to be reachable outside the container |
77
+ | `METRICS_PORT` | `9000` | Metrics port |
78
+ | `PUID` | `0` | Do not change; see [Why `PUID=0`](#why-puid0) |
79
+ | `OMEGGA_NONINTERACTIVE` | `true` | Hidden. Refuse auth prompts the console cannot answer |
80
+ | `SKIP_STEAMCMD_PROMPT` | `true` | Hidden. Do not change |
81
+ | `PACKAGE_NOTIFIER` | `false` | Hidden. Omegga comes from the image, not npm |
82
+ | `STEAM_NOTIFIER` | `false` | Hidden |
83
+
84
+ `--update` in `OMEGGA_FLAGS` checks Steam for a Brickadia update on every
85
+ start. It keeps the game current at the cost of not starting at all when Steam
86
+ is unreachable.
87
+
88
+ Debug logging goes through `OMEGGA_FLAGS=--debug`, not the `BRICKADIA_DEBUG`
89
+ environment variable. Omegga treats that variable as set-or-unset, so the
90
+ string `"false"` would enable it, and Pterodactyl materialises every declared
91
+ variable into the environment, with no way to leave one unset.
92
+
93
+ ## Ports in the config file
94
+
95
+ The egg drives ports through `BRICKADIA_PORT` and `OMEGGA_PORT` in the
96
+ environment, which override `omegga-config.yml`. It also keeps the two port
97
+ keys in the file itself in sync with the allocations, so the web UI and
98
+ `omegga info` report the ports the server is really on.
99
+
100
+ Everything else in `omegga-config.yml` is yours: edit it from the file manager
101
+ or the web UI. The egg only touches `server.port` and `omegga.port`.
102
+
103
+ ## Web UI over HTTPS
104
+
105
+ Omegga's web UI defaults to `https` with a self-signed certificate, so browsers
106
+ warn on first visit. To use a real certificate, put a reverse proxy in front of
107
+ the allocation and see [HTTPS with a real certificate](https.md).
108
+
109
+ ## Stopping
110
+
111
+ The egg stops the server by sending `SIGINT` (`^C`), which Omegga handles
112
+ gracefully. Its startup is considered complete when it logs
113
+ `Server has started`.
114
+
115
+ ## Limitations
116
+
117
+ - The published image is **amd64 only**. Omegga will not run on ARM nodes.
118
+ - SFTP reaches the server volume, but the Brickadia install lives in `$HOME`
119
+ inside the same volume and is large; avoid syncing it wholesale.
120
+ - The first start downloads Brickadia before the server becomes usable. The
121
+ console shows steamcmd progress during this; it is not stuck.
122
+
123
+ ## Why `PUID=0`
124
+
125
+ Wings runs an egg's install script as the install image's **own default user**,
126
+ and mounts the script from a root-owned `0700` directory. The Omegga image's
127
+ entrypoint drops privileges to its unprivileged `steam` user, which then cannot
128
+ read the script:
129
+
130
+ ```
131
+ bash: /mnt/install/install.sh: Permission denied
132
+ ```
133
+
134
+ `PUID=0` tells the entrypoint not to drop, which is the documented way to keep
135
+ it as root (see [Containers](../containers.md#file-ownership)).
136
+
137
+ It has no effect on the server container. Wings sets the container user
138
+ explicitly there, so the entrypoint sees a non-root uid and execs straight
139
+ through without reading `PUID` at all. Wings also chowns the server volume to
140
+ that user on start, so the root-owned files the install script leaves behind
141
+ are corrected before Omegga ever runs.
142
+
143
+ The entrypoint's Pterodactyl branch deliberately does not apply here: install
144
+ scripts arrive as an explicit `bash /mnt/install/install.sh` with `STARTUP` set
145
+ as well, and have to run as given rather than being replaced by the startup
146
+ command.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omegga",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "Brickadia server installer, updater, manager, wrapper, configurator, and automator",
5
5
  "engines": {
6
6
  "node": ">=23.0.0"