omegga 1.11.0 → 1.13.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 +20 -0
- package/README.md +2 -0
- package/dist/brickadia/config.js +1 -1
- package/dist/brickadia/config.js.map +1 -1
- package/dist/brickadia/server.js +20 -18
- package/dist/brickadia/server.js.map +1 -1
- package/dist/cli/auth.js +1 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/plugin.js +47 -22
- package/dist/cli/plugin.js.map +1 -1
- package/dist/cli/terminal.js +137 -28
- package/dist/cli/terminal.js.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/reader.js.map +1 -1
- package/dist/config/types.js +1 -0
- package/dist/config/types.js.map +1 -1
- package/dist/config/writer.js +1 -1
- package/dist/config/writer.js.map +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/main.js +24 -21
- package/dist/main.js.map +1 -1
- package/dist/omegga/auth.js.map +1 -1
- package/dist/omegga/commandInjector.js +88 -77
- package/dist/omegga/commandInjector.js.map +1 -1
- package/dist/omegga/logWrangler.js +9 -10
- package/dist/omegga/logWrangler.js.map +1 -1
- package/dist/omegga/matchers/auth.js +3 -3
- package/dist/omegga/matchers/auth.js.map +1 -1
- package/dist/omegga/matchers/chat.js +4 -4
- package/dist/omegga/matchers/chat.js.map +1 -1
- package/dist/omegga/matchers/command.js +4 -4
- package/dist/omegga/matchers/command.js.map +1 -1
- package/dist/omegga/matchers/exit.js +1 -1
- package/dist/omegga/matchers/exit.js.map +1 -1
- package/dist/omegga/matchers/index.js.map +1 -1
- package/dist/omegga/matchers/init.js +1 -1
- package/dist/omegga/matchers/init.js.map +1 -1
- package/dist/omegga/matchers/interact.js +17 -21
- package/dist/omegga/matchers/interact.js.map +1 -1
- package/dist/omegga/matchers/join.js +7 -7
- package/dist/omegga/matchers/join.js.map +1 -1
- package/dist/omegga/matchers/leave.js +4 -3
- package/dist/omegga/matchers/leave.js.map +1 -1
- package/dist/omegga/matchers/mapChange.js +1 -1
- package/dist/omegga/matchers/mapChange.js.map +1 -1
- package/dist/omegga/matchers/minigameJoin.js +2 -2
- package/dist/omegga/matchers/minigameJoin.js.map +1 -1
- package/dist/omegga/matchers/version.js.map +1 -1
- package/dist/omegga/matchers/wire.js +2 -2
- package/dist/omegga/matchers/wire.js.map +1 -1
- package/dist/omegga/player.js +91 -88
- package/dist/omegga/player.js.map +1 -1
- package/dist/omegga/plugin/interface.js +19 -10
- package/dist/omegga/plugin/interface.js.map +1 -1
- package/dist/omegga/plugin/plugin_jsonrpc_stdio.js +88 -82
- package/dist/omegga/plugin/plugin_jsonrpc_stdio.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js +75 -70
- package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_safe.js +30 -24
- package/dist/omegga/plugin/plugin_node_safe.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_unsafe.js +9 -4
- package/dist/omegga/plugin/plugin_node_unsafe.js.map +1 -1
- package/dist/omegga/plugin.js +7 -7
- package/dist/omegga/plugin.js.map +1 -1
- package/dist/omegga/server.js +41 -38
- package/dist/omegga/server.js.map +1 -1
- package/dist/omegga/wrapper.js.map +1 -1
- package/dist/plugin.js.map +1 -1
- package/dist/updater/steam.js +20 -3
- package/dist/updater/steam.js.map +1 -1
- package/dist/util/brick/checkBounds.js.map +1 -1
- package/dist/util/brick/displayName.js +1 -1
- package/dist/util/brick/displayName.js.map +1 -1
- package/dist/util/brick/getBounds.js +4 -3
- package/dist/util/brick/getBounds.js.map +1 -1
- package/dist/util/brick/getBrickSize.js +2 -2
- package/dist/util/brick/getBrickSize.js.map +1 -1
- package/dist/util/brick/getScaleAxis.js +1 -1
- package/dist/util/brick/getScaleAxis.js.map +1 -1
- package/dist/util/brick/rotate.js.map +1 -1
- package/dist/util/brick/setOwnership.js.map +1 -1
- package/dist/util/color.js +31 -15
- package/dist/util/color.js.map +1 -1
- package/dist/util/index.js.map +1 -1
- package/dist/version.js.map +1 -1
- package/dist/webserver/backend/database.js +45 -3
- package/dist/webserver/backend/database.js.map +1 -1
- package/dist/webserver/backend/index.js +6 -4
- package/dist/webserver/backend/index.js.map +1 -1
- package/dist/webserver/backend/metrics.js +1 -0
- package/dist/webserver/backend/metrics.js.map +1 -1
- package/dist/webserver/backend/permissions.js.map +1 -1
- package/dist/webserver/backend/router/plugin.js +6 -6
- package/dist/webserver/backend/router/plugin.js.map +1 -1
- package/dist/webserver/backend/router/user.js +53 -0
- package/dist/webserver/backend/router/user.js.map +1 -1
- package/dist/webserver/backend/router/world.js +1 -1
- package/dist/webserver/backend/router/world.js.map +1 -1
- package/dist/webserver/backend/scopes.js +6 -0
- package/dist/webserver/backend/scopes.js.map +1 -1
- package/dist/worker.js +30 -28
- package/dist/worker.js.map +1 -1
- package/eslint.config.mjs +109 -38
- package/package.json +11 -9
- package/public/app.html +135 -5
- package/public/assets/IconWorldPlus-Bzt4-NTF.js +2 -0
- package/public/assets/IconWorldPlus-Bzt4-NTF.js.map +1 -0
- package/public/assets/app-kNLgsOPx.js +7 -0
- package/public/assets/app-kNLgsOPx.js.map +1 -0
- package/public/assets/{index-5EkjXNMi.js → index-QURAMkP4.js} +2 -2
- package/public/assets/{index-5EkjXNMi.js.map → index-QURAMkP4.js.map} +1 -1
- package/public/assets/shared/{@components-VkA0DIz6.js → @components--CUpATJw.js} +2 -2
- package/public/assets/shared/@components--CUpATJw.js.map +1 -0
- package/public/assets/shared/{@hooks-CiJaUL6_.js → @hooks-CBm94p6G.js} +2 -2
- package/public/assets/shared/{@hooks-CiJaUL6_.js.map → @hooks-CBm94p6G.js.map} +1 -1
- package/public/assets/shared/@tabler_icons-react-B98xAreb.js +3 -0
- package/public/assets/shared/{@tabler_icons-react-B4130bhe.js.map → @tabler_icons-react-B98xAreb.js.map} +1 -1
- package/public/auth.html +71 -1
- package/templates/safe-ts/omegga.d.ts +632 -173
- package/public/assets/IconWorldPlus-DKSZjbqh.js +0 -2
- package/public/assets/IconWorldPlus-DKSZjbqh.js.map +0 -1
- package/public/assets/app-DvPQUQnE.js +0 -7
- package/public/assets/app-DvPQUQnE.js.map +0 -1
- package/public/assets/shared/@components-VkA0DIz6.js.map +0 -1
- package/public/assets/shared/@tabler_icons-react-B4130bhe.js +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
## Latest
|
|
4
4
|
|
|
5
|
+
## 1.13.0 - 2026-08-10
|
|
6
|
+
|
|
7
|
+
- Add `server.remoteFiles` config (default `true`); when `false`, the server launches with `-NoRemoteFileAccess`
|
|
8
|
+
- Print the new game version (like the `Launching Brickadia Server` log) when a server update finishes
|
|
9
|
+
- Bump brs-js to 3.7.0 for EA 3.1
|
|
10
|
+
|
|
11
|
+
## 1.12.0 - 2026-08-05
|
|
12
|
+
|
|
13
|
+
Web UI user management (ownership granting, self-rename, new `/user` terminal subcommands) and a typing/lint cleanup across the codebase.
|
|
14
|
+
|
|
15
|
+
- Web UI: Owners can grant ownership to another user from the user inspector (confirms with password, and a TOTP code when MFA is enabled)
|
|
16
|
+
- Web UI: Users can rename themselves from the account view with the new `user.rename` permission; new names are checked case-insensitively so users can't take another user's name
|
|
17
|
+
- Terminal: `/user` gains `rename`, `disable`, `enable`, `delete`, `grantowner`, and `revokeowner` subcommands; running `/user` alone lists usage like `/worlds`
|
|
18
|
+
- Terminal: Revoking ownership is console-only and refuses to demote the last remaining owner
|
|
19
|
+
- Fix double indentation of the player list in `/status`
|
|
20
|
+
- Fix type errors across the entire codebase; both the backend and frontend tsconfigs typecheck strict
|
|
21
|
+
- Set up eslint and fix all lints
|
|
22
|
+
- Build: Remove the legacy `build:old` (tspc) script and its `ts-patch`/`typescript-transform-paths` dependencies, and fix `npm run dts`
|
|
23
|
+
- CI: Run eslint and both typechecks on every push
|
|
24
|
+
|
|
5
25
|
## 1.11.0 - 2026-07-19
|
|
6
26
|
|
|
7
27
|
- Add `/version` terminal command, warning when the binary on disk differs from the running build
|
package/README.md
CHANGED
|
@@ -1087,6 +1087,8 @@ omegga:
|
|
|
1087
1087
|
server:
|
|
1088
1088
|
port: 7777 # game server port
|
|
1089
1089
|
map: Plate # map name
|
|
1090
|
+
# when false, the server launches with -NoRemoteFileAccess
|
|
1091
|
+
remoteFiles: true
|
|
1090
1092
|
# When branch is present, steamcmd is not used
|
|
1091
1093
|
#branch: release:release-server # branch alias:branch name
|
|
1092
1094
|
steambeta: public # try `unstable`
|
package/dist/brickadia/config.js
CHANGED
|
@@ -22,7 +22,7 @@ ServerDescription=${config.server.description || ""}
|
|
|
22
22
|
ServerPassword=${config.server.password || ""}
|
|
23
23
|
MaxPlayers=${config.server.players || 20}
|
|
24
24
|
bPubliclyListed=${config.server.publiclyListed ?? true ? "True" : "False"}
|
|
25
|
-
WelcomeMessage="${config.server.welcomeMessage?.replace(
|
|
25
|
+
WelcomeMessage="${config.server.welcomeMessage?.replace(/\\/g, "\\\\").replace(/"/g, '\\"') || ""}"`
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
function read() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sources":["../../src/brickadia/config.ts"],"sourcesContent":["import { IConfig } from '@config/types';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport * as file from '../util/file';\n\nimport { CONFIG_SAVED_DIR } from '@/softconfig';\nconst CONFIG_PATH = 'Config/LinuxServer';\nconst SERVER_SETTINGS = 'GameUserSettings.ini';\n\n// Function that writes config\nexport function write(serverPath: string, config: IConfig) {\n const configPath = path.join(\n serverPath,\n config.server.savedDir ?? CONFIG_SAVED_DIR,\n CONFIG_PATH,\n );\n const settingsPath = path.join(configPath, SERVER_SETTINGS);\n\n file.mkdir(configPath);\n\n fs.writeFileSync(\n settingsPath,\n `[Server__BP_ServerSettings_General_C BP_ServerSettings_General_C]\nServerName=${config.server.name || ''}\nServerDescription=${config.server.description || ''}\nServerPassword=${config.server.password || ''}\nMaxPlayers=${config.server.players || 20}\nbPubliclyListed=${(config.server.publiclyListed ?? true) ? 'True' : 'False'}\nWelcomeMessage=\"${config.server.welcomeMessage?.replace(
|
|
1
|
+
{"version":3,"file":"config.js","sources":["../../src/brickadia/config.ts"],"sourcesContent":["import { type IConfig } from '@config/types';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport * as file from '../util/file';\n\nimport { CONFIG_SAVED_DIR } from '@/softconfig';\nconst CONFIG_PATH = 'Config/LinuxServer';\nconst SERVER_SETTINGS = 'GameUserSettings.ini';\n\n// Function that writes config\nexport function write(serverPath: string, config: IConfig) {\n const configPath = path.join(\n serverPath,\n config.server.savedDir ?? CONFIG_SAVED_DIR,\n CONFIG_PATH,\n );\n const settingsPath = path.join(configPath, SERVER_SETTINGS);\n\n file.mkdir(configPath);\n\n fs.writeFileSync(\n settingsPath,\n `[Server__BP_ServerSettings_General_C BP_ServerSettings_General_C]\nServerName=${config.server.name || ''}\nServerDescription=${config.server.description || ''}\nServerPassword=${config.server.password || ''}\nMaxPlayers=${config.server.players || 20}\nbPubliclyListed=${(config.server.publiclyListed ?? true) ? 'True' : 'False'}\nWelcomeMessage=\"${\n config.server.welcomeMessage\n ?.replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"') || ''\n }\"`,\n );\n\n /*\n[Server__BP_ServerSettings_General_C BP_ServerSettings_General_C]\nServerTypeIndex2=1\nServerName=\nServerDescription=\nServerPassword=\nMaxPlayers=30\nbPubliclyListed=True\nWelcomeMessage=\"<color=\\\"0055ff\\\">Welcome to <b>{2}</>, {1}.</><>a\"\nbGlobalRulesetSelfDamage=True\nbGlobalRulesetPhysicsDamage=False\nbGlobalRulesetEnableCameraBlockedEffects=False\nUploadTimeout=5.000000\nMaxPrefabBricks=1000\nMaxPrefabComponents=20\nMaxPrefabSize=(X=1000,Y=1000,Z=1000)\nMaxPhysicsObjects=2000\nMaxPhysicsObjectsPerUser=50\nMaxPlacementBricks=2000\nMaxPlacementEntities=10\nbEnforceApplicatorLimits=False\nTemplatePlacementTimeout=2.000000\nMaxSelectionBoxSize=(X=1000,Y=1000,Z=1000)\nMaxSelectedBricks=1000\nSelectionTimeout=2.000000\n\n[Server__BP_ServerSettingsAutoSave_C BP_ServerSettingsAutoSave_C]\nbEnableAutoSave=True\nbAnnounceAutoSave=True\nAutoSaveInterval=300.000000\nbIncludeScreenshot=False\n */\n}\n\nexport function read() {\n // TODO: Implement server config reading\n}\n"],"names":["CONFIG_SAVED_DIR","file.mkdir"],"mappings":";;;;;;AAOA,MAAM,cAAc;AACpB,MAAM,kBAAkB;AAGjB,SAAS,MAAM,YAAoB,QAAiB;AACzD,QAAM,aAAa,KAAK;AAAA,IACtB;AAAA,IACA,OAAO,OAAO,YAAYA,WAAAA;AAAAA,IAC1B;AAAA,EAAA;AAEF,QAAM,eAAe,KAAK,KAAK,YAAY,eAAe;AAE1DC,OAAAA,MAAW,UAAU;AAErB,KAAG;AAAA,IACD;AAAA,IACA;AAAA,aACS,OAAO,OAAO,QAAQ,EAAE;AAAA,oBACjB,OAAO,OAAO,eAAe,EAAE;AAAA,iBAClC,OAAO,OAAO,YAAY,EAAE;AAAA,aAChC,OAAO,OAAO,WAAW,EAAE;AAAA,kBACrB,OAAO,OAAO,kBAAkB,OAAQ,SAAS,OAAO;AAAA,kBAErE,OAAO,OAAO,gBACV,QAAQ,OAAO,MAAM,EACtB,QAAQ,MAAM,KAAK,KAAK,EAC7B;AAAA,EAAA;AAmCJ;AAEO,SAAS,OAAO;AAEvB;;;"}
|
package/dist/brickadia/server.js
CHANGED
|
@@ -108,7 +108,9 @@ class BrickadiaServer extends EventEmitter {
|
|
|
108
108
|
{ source: "config", file: this.getConfigWorld() },
|
|
109
109
|
{ source: "env", file: this.getEnvWorld() }
|
|
110
110
|
];
|
|
111
|
-
return candidates.find(
|
|
111
|
+
return candidates.find(
|
|
112
|
+
(c) => !!c.file && this.worldExists(c.file)
|
|
113
|
+
) ?? null;
|
|
112
114
|
}
|
|
113
115
|
/**
|
|
114
116
|
* Resolve the path to the game server binary for steam/override installs.
|
|
@@ -214,6 +216,8 @@ class BrickadiaServer extends EventEmitter {
|
|
|
214
216
|
world && `-World="${world.file}"`,
|
|
215
217
|
"-NotInstalled",
|
|
216
218
|
"-log",
|
|
219
|
+
// remote file access is on unless explicitly disabled in the config
|
|
220
|
+
this.config.server.remoteFiles === false ? "-NoRemoteFileAccess" : null,
|
|
217
221
|
wsl.checkWsl() === 1 ? "-OneThread" : null,
|
|
218
222
|
this.path ? `-UserDir="${this.path}"` : null,
|
|
219
223
|
token ? `-Token="${token}"` : null,
|
|
@@ -224,23 +228,21 @@ class BrickadiaServer extends EventEmitter {
|
|
|
224
228
|
// remove password argument if not provided or token is provided
|
|
225
229
|
`-port="${this.config.server.port}"`,
|
|
226
230
|
this.config.server.launchArgs
|
|
227
|
-
].filter(
|
|
231
|
+
].filter((arg) => typeof arg === "string").filter((arg) => arg.length > 0);
|
|
228
232
|
logger.default.verbose(
|
|
229
233
|
"Params for spawn",
|
|
230
234
|
params.join(" ").replace(/-User=".*?"/, '-User="<hidden>"').replace(/-Password=".*?"/, '-Password="<hidden>"').replace(/-Token=".*?"/, '-Token="<hidden>"').replace(/-Cookie=".*?"/, '-Cookie="<hidden>"').replace(/-Cookie=\S+/, "-Cookie=<hidden>")
|
|
231
235
|
);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
);
|
|
237
|
-
this.#child.stdin.setDefaultEncoding("utf8");
|
|
236
|
+
const child = node_child_process.spawn("stdbuf", params);
|
|
237
|
+
this.#child = child;
|
|
238
|
+
logger.default.verbose("Spawn process", child.pid ?? "failed".red);
|
|
239
|
+
child.stdin.setDefaultEncoding("utf8");
|
|
238
240
|
this.#outInterface = readline.createInterface({
|
|
239
|
-
input:
|
|
241
|
+
input: child.stdout,
|
|
240
242
|
terminal: false
|
|
241
243
|
});
|
|
242
244
|
this.#errInterface = readline.createInterface({
|
|
243
|
-
input:
|
|
245
|
+
input: child.stderr,
|
|
244
246
|
terminal: false
|
|
245
247
|
});
|
|
246
248
|
this.attachListeners();
|
|
@@ -292,18 +294,18 @@ class BrickadiaServer extends EventEmitter {
|
|
|
292
294
|
}
|
|
293
295
|
// attaches proxy event listeners
|
|
294
296
|
attachListeners() {
|
|
295
|
-
this.#outInterface
|
|
296
|
-
this.#errInterface
|
|
297
|
-
this.#child
|
|
298
|
-
this.#child
|
|
297
|
+
this.#outInterface?.on("line", this.lineListener);
|
|
298
|
+
this.#errInterface?.on("line", this.errorListener);
|
|
299
|
+
this.#child?.on("exit", this.exitListener);
|
|
300
|
+
this.#child?.on("close", () => {
|
|
299
301
|
});
|
|
300
302
|
}
|
|
301
303
|
// removes previously attached proxy event listeners
|
|
302
304
|
detachListeners() {
|
|
303
|
-
this.#outInterface
|
|
304
|
-
this.#errInterface
|
|
305
|
-
this.#child
|
|
306
|
-
this.#child
|
|
305
|
+
this.#outInterface?.off("line", this.lineListener);
|
|
306
|
+
this.#errInterface?.off("line", this.errorListener);
|
|
307
|
+
this.#child?.off("exit", this.exitListener);
|
|
308
|
+
this.#child?.removeAllListeners("close");
|
|
307
309
|
}
|
|
308
310
|
// -- listeners for basic events (line, err, exit)
|
|
309
311
|
errorListener(line) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sources":["../../src/brickadia/server.ts"],"sourcesContent":["/*\n Brickadia Server Wrapper\n Manages IO with the game server\n*/\n\nimport Logger from '@/logger';\nimport {\n ACTIVE_WORLD_FILE,\n CONFIG_SAVED_DIR,\n GAME_BIN_PATH,\n getOverrideGameBinary,\n getSteamGameDir,\n getSteamInstallDir,\n} from '@/softconfig';\nimport { getGlobalToken } from '@cli/auth';\nimport { IConfig } from '@config/types';\nimport { checkWsl } from '@util/wsl';\nimport 'colors';\nimport { ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport EventEmitter from 'node:events';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { env } from 'node:process';\nimport readline from 'readline';\nimport stripAnsi from 'strip-ansi';\n\n// list of errors that can be solved by yelling at the user\nconst knownErrors: {\n name: string;\n solution?: string;\n match: RegExp;\n message?: string;\n}[] = [\n {\n name: 'MISSING_LIBGL',\n solution: 'apt-get install libgl1-mesa-glx libglib2.0-0',\n match:\n /error while loading shared libraries: libGL\\.so\\.1: cannot open shared object file/,\n },\n {\n name: 'MISSING_GLIB',\n solution: 'apt-get install libgl1-mesa-glx libglib2.0-0',\n match:\n /error while loading shared libraries: libgthread-2\\.0\\.so\\.0: cannot open shared object file/,\n },\n];\n\n/** Start a brickadia server */\nexport default class BrickadiaServer extends EventEmitter {\n #child: ChildProcessWithoutNullStreams = null;\n #errInterface: readline.Interface = null;\n #outInterface: readline.Interface = null;\n\n config: IConfig;\n path: string;\n\n constructor(dataPath: string, config: IConfig) {\n super();\n\n this.config = config;\n // use the data path if it's absolute, otherwise build an absolute path\n this.path =\n path.isAbsolute(dataPath) || dataPath.startsWith('/')\n ? dataPath\n : path.join(process.cwd(), dataPath);\n\n this.lineListener = this.lineListener.bind(this);\n this.errorListener = this.errorListener.bind(this);\n this.exitListener = this.exitListener.bind(this);\n }\n\n getActiveWorldFile(): string {\n return path.join(this.path, ACTIVE_WORLD_FILE);\n }\n\n /** A world specified by the active world file */\n getActiveWorld(): string | null {\n const activeWorldFile = this.getActiveWorldFile();\n if (existsSync(activeWorldFile)) {\n try {\n return readFileSync(activeWorldFile, 'utf8').trim();\n } catch (err) {\n Logger.errorp(\n 'Failed to read active world file',\n activeWorldFile.yellow,\n err,\n );\n return null;\n }\n }\n return null;\n }\n\n /** Set the world to use next startup */\n setActiveWorld(world: string | null): boolean {\n const activeWorldFile = this.getActiveWorldFile();\n if (!world || world === null) {\n if (existsSync(activeWorldFile)) {\n Logger.verbose('Removing active world file', activeWorldFile.yellow);\n unlinkSync(activeWorldFile);\n }\n return true;\n }\n\n if (!this.worldExists(world)) {\n Logger.verbose(\n 'Cannot set active world to',\n world.yellow,\n 'as it does not exist',\n );\n return false;\n }\n\n Logger.verbose('Setting active world to', world.yellow);\n try {\n writeFileSync(activeWorldFile, world, 'utf8');\n return true;\n } catch (err) {\n Logger.errorp(\n 'Failed to write active world file',\n activeWorldFile.yellow,\n err,\n );\n return false;\n }\n }\n\n /** A world specified by the config */\n getConfigWorld(): string | null {\n return this.config?.server?.world ?? null;\n }\n\n /** A world specified by the BRICKADIA_WORLD env variable */\n getEnvWorld(): string | null {\n return env.BRICKADIA_WORLD || null;\n }\n\n /** Check if a world exists */\n worldExists(world: string): boolean {\n const savedDir = this.config?.server?.savedDir ?? CONFIG_SAVED_DIR;\n const worldPath = path.join(this.path, savedDir, 'Worlds', world + '.brdb');\n return existsSync(worldPath);\n }\n\n /** Get the world that will be used next startup */\n getNextWorld() {\n const candidates = [\n { source: 'file', file: this.getActiveWorld() },\n { source: 'config', file: this.getConfigWorld() },\n { source: 'env', file: this.getEnvWorld() },\n ];\n\n return (\n candidates.find(({ file }) => file && this.worldExists(file)) ?? null\n );\n }\n\n /**\n * Resolve the path to the game server binary for steam/override installs.\n * Returns null for launcher-managed installs, where the binary lives in a\n * branch directory the launcher owns and isn't known statically here.\n */\n getGameBinaryPath(): string | null {\n const overrideBinary = getOverrideGameBinary();\n if (overrideBinary) return overrideBinary;\n\n // a configured branch means the launcher manages the install, not steam\n const isSteam = !this.config.server.branch;\n if (!isSteam) return null;\n\n const steamBeta = this.config.server.steambeta ?? 'main';\n return path.join(\n getSteamInstallDir(), // steam install directory\n steamBeta, // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n }\n\n // start the server child process\n start() {\n const {\n email,\n password,\n token: confToken,\n }: { email?: string; password?: string; token?: string } = this.config\n .credentials || {};\n\n const token = confToken || process.env.BRICKADIA_TOKEN || getGlobalToken();\n\n if (token) {\n Logger.verbose('Starting server with hosting token');\n } else {\n Logger.verbose(\n 'Starting server',\n (!email && !password ? 'without' : 'with').yellow,\n 'credentials',\n );\n }\n\n const isSteam = !this.config.server.branch;\n const steamBeta = this.config.server.steambeta ?? 'main';\n const overrideBinary = getOverrideGameBinary();\n const steamBinary = path.join(\n getSteamInstallDir(), // steam install directory\n steamBeta, // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n\n let gameBinary = this.getGameBinaryPath() ?? steamBinary;\n\n if (overrideBinary) {\n if (!existsSync(overrideBinary)) {\n Logger.error(\n 'Override binary',\n overrideBinary.yellow,\n 'does not exist!',\n );\n throw new Error(`Override binary ${overrideBinary} does not exist!`);\n }\n\n Logger.verbose(\n 'Using override binary',\n overrideBinary.yellow,\n 'instead of',\n steamBinary.yellow,\n );\n gameBinary = overrideBinary;\n } else if (isSteam) {\n Logger.verbose('Using steam binary', steamBeta.yellow);\n } else {\n Logger.verbose(\n 'Running',\n (this.config.server.__LOCAL\n ? path.join(__dirname, '../../tools/brickadia.sh')\n : 'brickadia launcher'\n ).yellow,\n );\n if (typeof this.config.server.branch === 'string')\n Logger.verbose('Using branch', this.config.server.branch.yellow);\n }\n\n // handle local launcher support\n const launchArgs = isSteam\n ? [gameBinary]\n : [\n this.config.server.__LOCAL\n ? path.join(__dirname, '../../tools/brickadia.sh')\n : 'brickadia',\n this.config.server.branch && `--branch=${this.config.server.branch}`,\n '--server',\n '--',\n ];\n\n const world = this.getNextWorld();\n if (world) {\n Logger.verbose(\n 'Using world',\n world.file.yellow,\n 'from',\n world.source.yellow,\n );\n } else if (this.config.server.map) {\n Logger.verbose('Using map', this.config.server.map.yellow, 'from config');\n }\n\n const params = [\n '--output=L',\n '--',\n ...launchArgs,\n !world &&\n this.config.server.map &&\n `-Environment=\"${this.config.server.map}\"`,\n world && `-World=\"${world.file}\"`,\n '-NotInstalled',\n '-log',\n checkWsl() === 1 ? '-OneThread' : null,\n this.path ? `-UserDir=\"${this.path}\"` : null,\n token ? `-Token=\"${token}\"` : null, // remove token argument if not provided\n !token && email ? `-User=\"${email}\"` : null, // remove email argument if not provided or token is provided\n !token && password ? `-Password=\"${password}\"` : null, // remove password argument if not provided or token is provided\n `-port=\"${this.config.server.port}\"`,\n this.config.server.launchArgs,\n ].filter(Boolean); // remove unused arguments\n Logger.verbose(\n 'Params for spawn',\n params\n .join(' ')\n .replace(/-User=\".*?\"/, '-User=\"<hidden>\"')\n .replace(/-Password=\".*?\"/, '-Password=\"<hidden>\"')\n .replace(/-Token=\".*?\"/, '-Token=\"<hidden>\"')\n .replace(/-Cookie=\".*?\"/, '-Cookie=\"<hidden>\"')\n .replace(/-Cookie=\\S+/, '-Cookie=<hidden>'),\n );\n\n // Either unbuffer or stdbuf must be used because brickadia's output is buffered\n // this means that multiple lines can be bundled together if the output buffer is not full\n // unfortunately without stdbuf or unbuffer, the output would not happen immediately\n this.#child = spawn('stdbuf', params);\n\n Logger.verbose(\n 'Spawn process',\n this.#child ? this.#child.pid : 'failed'.red,\n );\n\n this.#child.stdin.setDefaultEncoding('utf8');\n this.#outInterface = readline.createInterface({\n input: this.#child.stdout,\n terminal: false,\n });\n this.#errInterface = readline.createInterface({\n input: this.#child.stderr,\n terminal: false,\n });\n this.attachListeners();\n Logger.verbose('Attached listeners');\n }\n\n // write a string to the child process\n write(line: string) {\n if (line.length >= 512) {\n // show a warning\n Logger.warn(\n 'WARNING'.yellow,\n 'The following line was called and is',\n 'longer than allowed limit'.red,\n );\n Logger.warn(line.replace(/\\n$/, ''));\n // throw a fake error to get the line number\n try {\n throw new Error('Console Line Too Long');\n } catch (err) {\n Logger.warn(err);\n }\n return;\n }\n if (this.#child) {\n Logger.verbose('WRITE'.green, line.replace(/\\n$/, ''));\n this.#child.stdin.write(line);\n }\n }\n\n // write a line to the child process\n writeln(line: string) {\n this.write(line + '\\n');\n }\n\n // forcibly kills the server\n stop() {\n if (!this.#child) {\n Logger.verbose('Cannot stop server as no subprocess exists');\n return;\n }\n\n Logger.verbose('Forcibly stopping server');\n // kill the process\n this.#child.kill('SIGINT');\n\n // ...kill it again just to make sure it's dead\n spawn('kill', ['-9', this.#child.pid + '']);\n }\n\n // detaches listeners\n cleanup() {\n if (!this.#child) return;\n\n Logger.verbose('Cleaning up brickadia server');\n\n // detach listener\n this.detachListeners();\n\n this.#child = null;\n this.#outInterface = null;\n this.#errInterface = null;\n }\n\n // attaches proxy event listeners\n attachListeners() {\n this.#outInterface.on('line', this.lineListener);\n this.#errInterface.on('line', this.errorListener);\n this.#child.on('exit', this.exitListener);\n this.#child.on('close', () => {});\n }\n\n // removes previously attached proxy event listeners\n detachListeners() {\n this.#outInterface.off('line', this.lineListener);\n this.#errInterface.off('line', this.errorListener);\n this.#child.off('exit', this.exitListener);\n this.#child.removeAllListeners('close');\n }\n\n // -- listeners for basic events (line, err, exit)\n errorListener(line: string) {\n Logger.verbose('ERROR'.red, line);\n this.emit('err', line);\n for (const { match, solution, name, message } of knownErrors) {\n if (line.match(match)) {\n Logger.error(\n `Encountered ${name.red}. ${\n solution ? 'Known fix:\\n ' + solution : message || 'Unknown error.'\n }`,\n );\n }\n }\n }\n\n exitListener(...args: any[]) {\n Logger.verbose('Exit listener fired');\n this.emit('closed', ...args);\n this.cleanup();\n }\n\n lineListener(line: string) {\n this.emit('line', stripAnsi(line));\n }\n}\n"],"names":["ACTIVE_WORLD_FILE","existsSync","readFileSync","Logger","unlinkSync","writeFileSync","env","CONFIG_SAVED_DIR","getOverrideGameBinary","getSteamInstallDir","getSteamGameDir","GAME_BIN_PATH","getGlobalToken","checkWsl","spawn"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sources":["../../src/brickadia/server.ts"],"sourcesContent":["/*\n Brickadia Server Wrapper\n Manages IO with the game server\n*/\n\nimport Logger from '@/logger';\nimport {\n ACTIVE_WORLD_FILE,\n CONFIG_SAVED_DIR,\n GAME_BIN_PATH,\n getOverrideGameBinary,\n getSteamGameDir,\n getSteamInstallDir,\n} from '@/softconfig';\nimport { getGlobalToken } from '@cli/auth';\nimport { type IConfig } from '@config/types';\nimport { checkWsl } from '@util/wsl';\nimport 'colors';\nimport { type ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport EventEmitter from 'node:events';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { env } from 'node:process';\nimport readline from 'readline';\nimport stripAnsi from 'strip-ansi';\n\n// list of errors that can be solved by yelling at the user\nconst knownErrors: {\n name: string;\n solution?: string;\n match: RegExp;\n message?: string;\n}[] = [\n {\n name: 'MISSING_LIBGL',\n solution: 'apt-get install libgl1-mesa-glx libglib2.0-0',\n match:\n /error while loading shared libraries: libGL\\.so\\.1: cannot open shared object file/,\n },\n {\n name: 'MISSING_GLIB',\n solution: 'apt-get install libgl1-mesa-glx libglib2.0-0',\n match:\n /error while loading shared libraries: libgthread-2\\.0\\.so\\.0: cannot open shared object file/,\n },\n];\n\n/** Start a brickadia server */\nexport default class BrickadiaServer extends EventEmitter {\n #child: ChildProcessWithoutNullStreams | null = null;\n #errInterface: readline.Interface | null = null;\n #outInterface: readline.Interface | null = null;\n\n config: IConfig;\n path: string;\n\n constructor(dataPath: string, config: IConfig) {\n super();\n\n this.config = config;\n // use the data path if it's absolute, otherwise build an absolute path\n this.path =\n path.isAbsolute(dataPath) || dataPath.startsWith('/')\n ? dataPath\n : path.join(process.cwd(), dataPath);\n\n this.lineListener = this.lineListener.bind(this);\n this.errorListener = this.errorListener.bind(this);\n this.exitListener = this.exitListener.bind(this);\n }\n\n getActiveWorldFile(): string {\n return path.join(this.path, ACTIVE_WORLD_FILE);\n }\n\n /** A world specified by the active world file */\n getActiveWorld(): string | null {\n const activeWorldFile = this.getActiveWorldFile();\n if (existsSync(activeWorldFile)) {\n try {\n return readFileSync(activeWorldFile, 'utf8').trim();\n } catch (err) {\n Logger.errorp(\n 'Failed to read active world file',\n activeWorldFile.yellow,\n err,\n );\n return null;\n }\n }\n return null;\n }\n\n /** Set the world to use next startup */\n setActiveWorld(world: string | null): boolean {\n const activeWorldFile = this.getActiveWorldFile();\n if (!world || world === null) {\n if (existsSync(activeWorldFile)) {\n Logger.verbose('Removing active world file', activeWorldFile.yellow);\n unlinkSync(activeWorldFile);\n }\n return true;\n }\n\n if (!this.worldExists(world)) {\n Logger.verbose(\n 'Cannot set active world to',\n world.yellow,\n 'as it does not exist',\n );\n return false;\n }\n\n Logger.verbose('Setting active world to', world.yellow);\n try {\n writeFileSync(activeWorldFile, world, 'utf8');\n return true;\n } catch (err) {\n Logger.errorp(\n 'Failed to write active world file',\n activeWorldFile.yellow,\n err,\n );\n return false;\n }\n }\n\n /** A world specified by the config */\n getConfigWorld(): string | null {\n return this.config?.server?.world ?? null;\n }\n\n /** A world specified by the BRICKADIA_WORLD env variable */\n getEnvWorld(): string | null {\n return env.BRICKADIA_WORLD || null;\n }\n\n /** Check if a world exists */\n worldExists(world: string): boolean {\n const savedDir = this.config?.server?.savedDir ?? CONFIG_SAVED_DIR;\n const worldPath = path.join(this.path, savedDir, 'Worlds', world + '.brdb');\n return existsSync(worldPath);\n }\n\n /** Get the world that will be used next startup */\n getNextWorld(): { source: string; file: string } | null {\n const candidates = [\n { source: 'file', file: this.getActiveWorld() },\n { source: 'config', file: this.getConfigWorld() },\n { source: 'env', file: this.getEnvWorld() },\n ];\n\n return (\n candidates.find(\n (c): c is { source: string; file: string } =>\n !!c.file && this.worldExists(c.file),\n ) ?? null\n );\n }\n\n /**\n * Resolve the path to the game server binary for steam/override installs.\n * Returns null for launcher-managed installs, where the binary lives in a\n * branch directory the launcher owns and isn't known statically here.\n */\n getGameBinaryPath(): string | null {\n const overrideBinary = getOverrideGameBinary();\n if (overrideBinary) return overrideBinary;\n\n // a configured branch means the launcher manages the install, not steam\n const isSteam = !this.config.server.branch;\n if (!isSteam) return null;\n\n const steamBeta = this.config.server.steambeta ?? 'main';\n return path.join(\n getSteamInstallDir(), // steam install directory\n steamBeta, // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n }\n\n // start the server child process\n start() {\n const {\n email,\n password,\n token: confToken,\n }: { email?: string; password?: string; token?: string } = this.config\n .credentials || {};\n\n const token = confToken || process.env.BRICKADIA_TOKEN || getGlobalToken();\n\n if (token) {\n Logger.verbose('Starting server with hosting token');\n } else {\n Logger.verbose(\n 'Starting server',\n (!email && !password ? 'without' : 'with').yellow,\n 'credentials',\n );\n }\n\n const isSteam = !this.config.server.branch;\n const steamBeta = this.config.server.steambeta ?? 'main';\n const overrideBinary = getOverrideGameBinary();\n const steamBinary = path.join(\n getSteamInstallDir(), // steam install directory\n steamBeta, // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n\n let gameBinary = this.getGameBinaryPath() ?? steamBinary;\n\n if (overrideBinary) {\n if (!existsSync(overrideBinary)) {\n Logger.error(\n 'Override binary',\n overrideBinary.yellow,\n 'does not exist!',\n );\n throw new Error(`Override binary ${overrideBinary} does not exist!`);\n }\n\n Logger.verbose(\n 'Using override binary',\n overrideBinary.yellow,\n 'instead of',\n steamBinary.yellow,\n );\n gameBinary = overrideBinary;\n } else if (isSteam) {\n Logger.verbose('Using steam binary', steamBeta.yellow);\n } else {\n Logger.verbose(\n 'Running',\n (this.config.server.__LOCAL\n ? path.join(__dirname, '../../tools/brickadia.sh')\n : 'brickadia launcher'\n ).yellow,\n );\n if (typeof this.config.server.branch === 'string')\n Logger.verbose('Using branch', this.config.server.branch.yellow);\n }\n\n // handle local launcher support\n const launchArgs = isSteam\n ? [gameBinary]\n : [\n this.config.server.__LOCAL\n ? path.join(__dirname, '../../tools/brickadia.sh')\n : 'brickadia',\n this.config.server.branch && `--branch=${this.config.server.branch}`,\n '--server',\n '--',\n ];\n\n const world = this.getNextWorld();\n if (world) {\n Logger.verbose(\n 'Using world',\n world.file.yellow,\n 'from',\n world.source.yellow,\n );\n } else if (this.config.server.map) {\n Logger.verbose('Using map', this.config.server.map.yellow, 'from config');\n }\n\n const params = [\n '--output=L',\n '--',\n ...launchArgs,\n !world &&\n this.config.server.map &&\n `-Environment=\"${this.config.server.map}\"`,\n world && `-World=\"${world.file}\"`,\n '-NotInstalled',\n '-log',\n // remote file access is on unless explicitly disabled in the config\n this.config.server.remoteFiles === false ? '-NoRemoteFileAccess' : null,\n checkWsl() === 1 ? '-OneThread' : null,\n this.path ? `-UserDir=\"${this.path}\"` : null,\n token ? `-Token=\"${token}\"` : null, // remove token argument if not provided\n !token && email ? `-User=\"${email}\"` : null, // remove email argument if not provided or token is provided\n !token && password ? `-Password=\"${password}\"` : null, // remove password argument if not provided or token is provided\n `-port=\"${this.config.server.port}\"`,\n this.config.server.launchArgs,\n ]\n .filter(arg => typeof arg === 'string')\n .filter(arg => arg.length > 0); // remove unused/empty arguments\n Logger.verbose(\n 'Params for spawn',\n params\n .join(' ')\n .replace(/-User=\".*?\"/, '-User=\"<hidden>\"')\n .replace(/-Password=\".*?\"/, '-Password=\"<hidden>\"')\n .replace(/-Token=\".*?\"/, '-Token=\"<hidden>\"')\n .replace(/-Cookie=\".*?\"/, '-Cookie=\"<hidden>\"')\n .replace(/-Cookie=\\S+/, '-Cookie=<hidden>'),\n );\n\n // Either unbuffer or stdbuf must be used because brickadia's output is buffered\n // this means that multiple lines can be bundled together if the output buffer is not full\n // unfortunately without stdbuf or unbuffer, the output would not happen immediately\n const child = spawn('stdbuf', params);\n this.#child = child;\n\n Logger.verbose('Spawn process', child.pid ?? 'failed'.red);\n\n child.stdin.setDefaultEncoding('utf8');\n this.#outInterface = readline.createInterface({\n input: child.stdout,\n terminal: false,\n });\n this.#errInterface = readline.createInterface({\n input: child.stderr,\n terminal: false,\n });\n this.attachListeners();\n Logger.verbose('Attached listeners');\n }\n\n // write a string to the child process\n write(line: string) {\n if (line.length >= 512) {\n // show a warning\n Logger.warn(\n 'WARNING'.yellow,\n 'The following line was called and is',\n 'longer than allowed limit'.red,\n );\n Logger.warn(line.replace(/\\n$/, ''));\n // throw a fake error to get the line number\n try {\n throw new Error('Console Line Too Long');\n } catch (err) {\n Logger.warn(err);\n }\n return;\n }\n if (this.#child) {\n Logger.verbose('WRITE'.green, line.replace(/\\n$/, ''));\n this.#child.stdin.write(line);\n }\n }\n\n // write a line to the child process\n writeln(line: string) {\n this.write(line + '\\n');\n }\n\n // forcibly kills the server\n stop() {\n if (!this.#child) {\n Logger.verbose('Cannot stop server as no subprocess exists');\n return;\n }\n\n Logger.verbose('Forcibly stopping server');\n // kill the process\n this.#child.kill('SIGINT');\n\n // ...kill it again just to make sure it's dead\n spawn('kill', ['-9', this.#child.pid + '']);\n }\n\n // detaches listeners\n cleanup() {\n if (!this.#child) return;\n\n Logger.verbose('Cleaning up brickadia server');\n\n // detach listener\n this.detachListeners();\n\n this.#child = null;\n this.#outInterface = null;\n this.#errInterface = null;\n }\n\n // attaches proxy event listeners\n attachListeners() {\n this.#outInterface?.on('line', this.lineListener);\n this.#errInterface?.on('line', this.errorListener);\n this.#child?.on('exit', this.exitListener);\n this.#child?.on('close', () => {});\n }\n\n // removes previously attached proxy event listeners\n detachListeners() {\n this.#outInterface?.off('line', this.lineListener);\n this.#errInterface?.off('line', this.errorListener);\n this.#child?.off('exit', this.exitListener);\n this.#child?.removeAllListeners('close');\n }\n\n // -- listeners for basic events (line, err, exit)\n errorListener(line: string) {\n Logger.verbose('ERROR'.red, line);\n this.emit('err', line);\n for (const { match, solution, name, message } of knownErrors) {\n if (line.match(match)) {\n Logger.error(\n `Encountered ${name.red}. ${\n solution ? 'Known fix:\\n ' + solution : message || 'Unknown error.'\n }`,\n );\n }\n }\n }\n\n exitListener(...args: any[]) {\n Logger.verbose('Exit listener fired');\n this.emit('closed', ...args);\n this.cleanup();\n }\n\n lineListener(line: string) {\n this.emit('line', stripAnsi(line));\n }\n}\n"],"names":["ACTIVE_WORLD_FILE","existsSync","readFileSync","Logger","unlinkSync","writeFileSync","env","CONFIG_SAVED_DIR","getOverrideGameBinary","getSteamInstallDir","getSteamGameDir","GAME_BIN_PATH","getGlobalToken","checkWsl","spawn"],"mappings":"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"}
|
package/dist/cli/auth.js
CHANGED
|
@@ -120,7 +120,7 @@ async function authFromPrompt({
|
|
|
120
120
|
console.log(">>".green, "Storing auth tokens...");
|
|
121
121
|
const authPath = path.join(
|
|
122
122
|
softconfig.default.CONFIG_HOME,
|
|
123
|
-
savedDir !== softconfig.default.CONFIG_SAVED_DIR ? savedDir : "",
|
|
123
|
+
savedDir && savedDir !== softconfig.default.CONFIG_SAVED_DIR ? savedDir : "",
|
|
124
124
|
authDir ?? softconfig.default.CONFIG_AUTH_DIR
|
|
125
125
|
);
|
|
126
126
|
file.mkdir(authPath);
|
package/dist/cli/auth.js.map
CHANGED
|
@@ -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
|
|
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 (from https://brickadia.com/account)',\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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"}
|
package/dist/cli/plugin.js
CHANGED
|
@@ -45,9 +45,11 @@ const transformers = [
|
|
|
45
45
|
}
|
|
46
46
|
];
|
|
47
47
|
const transformUrl = (url) => {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
for (const t of transformers) {
|
|
49
|
+
const match = url.match(t.pattern);
|
|
50
|
+
if (match?.groups) return t.fn(match.groups);
|
|
51
|
+
}
|
|
52
|
+
return { type: "raw", url };
|
|
51
53
|
};
|
|
52
54
|
let needsNL = false;
|
|
53
55
|
const rewriteLine = (...args) => {
|
|
@@ -65,7 +67,12 @@ const plg = (plugin2, ...args) => {
|
|
|
65
67
|
};
|
|
66
68
|
const plgLog = (plugin2, ...args) => {
|
|
67
69
|
if (logger.default.VERBOSE) plg(plugin2, ...args);
|
|
68
|
-
else
|
|
70
|
+
else
|
|
71
|
+
rewriteLine(
|
|
72
|
+
plugin2.name ?? ("url" in plugin2 ? plugin2.url : ""),
|
|
73
|
+
">>".green,
|
|
74
|
+
...args
|
|
75
|
+
);
|
|
69
76
|
};
|
|
70
77
|
const plgWarn = (plugin2, ...args) => {
|
|
71
78
|
if (needsNL) {
|
|
@@ -162,16 +169,17 @@ async function install(plugins, _options) {
|
|
|
162
169
|
);
|
|
163
170
|
log("Attempting to install", (plugins.length + "").yellow, "plugins...");
|
|
164
171
|
for (const pluginUrl of plugins) {
|
|
165
|
-
const
|
|
166
|
-
|
|
172
|
+
const transformed = transformUrl(pluginUrl);
|
|
173
|
+
let name = transformed.name;
|
|
174
|
+
if (!name) {
|
|
167
175
|
try {
|
|
168
|
-
|
|
169
|
-
plugin2.name = name.replace(/^omegga-/, "");
|
|
176
|
+
name = path.parse(transformed.url).name.replace(/^omegga-/, "");
|
|
170
177
|
} catch (e) {
|
|
171
|
-
console.error("!>".red, "Error parsing name from url",
|
|
178
|
+
console.error("!>".red, "Error parsing name from url", transformed.url);
|
|
172
179
|
break;
|
|
173
180
|
}
|
|
174
181
|
}
|
|
182
|
+
const plugin2 = { ...transformed, name };
|
|
175
183
|
log(
|
|
176
184
|
"Installing plugin",
|
|
177
185
|
plugin2.name.yellow,
|
|
@@ -210,7 +218,7 @@ async function install(plugins, _options) {
|
|
|
210
218
|
verboseLog("Changing permission of", postInstallPath);
|
|
211
219
|
fs.chmodSync(postInstallPath, "0755");
|
|
212
220
|
verboseLog("Executing bash file");
|
|
213
|
-
|
|
221
|
+
const { stdout, stderr } = await exec(postInstallPath, {
|
|
214
222
|
cwd: pluginPath,
|
|
215
223
|
shell: "bash"
|
|
216
224
|
});
|
|
@@ -242,7 +250,7 @@ async function update(pluginsNames, _options) {
|
|
|
242
250
|
return;
|
|
243
251
|
}
|
|
244
252
|
log("Checking", (plugins.length + "").yellow, "plugins for updates...");
|
|
245
|
-
|
|
253
|
+
const pluginsToUpdate = [];
|
|
246
254
|
for (const plugin2 of plugins) {
|
|
247
255
|
if (needsNL) {
|
|
248
256
|
console.log();
|
|
@@ -262,6 +270,7 @@ async function update(pluginsNames, _options) {
|
|
|
262
270
|
status = await git.status();
|
|
263
271
|
} catch (e) {
|
|
264
272
|
plgErr(plugin2, "Error getting status", e);
|
|
273
|
+
continue;
|
|
265
274
|
}
|
|
266
275
|
try {
|
|
267
276
|
if (status.files.some((f) => f.working_dir !== "?")) {
|
|
@@ -317,7 +326,7 @@ async function update(pluginsNames, _options) {
|
|
|
317
326
|
continue;
|
|
318
327
|
}
|
|
319
328
|
plgLog(plugin2, "Update available");
|
|
320
|
-
pluginsToUpdate.push(plugin2);
|
|
329
|
+
pluginsToUpdate.push({ ...plugin2, path: pluginPath, git });
|
|
321
330
|
} catch (e) {
|
|
322
331
|
plgErr(plugin2, "Error", e);
|
|
323
332
|
}
|
|
@@ -359,7 +368,7 @@ async function update(pluginsNames, _options) {
|
|
|
359
368
|
plgLog(plugin2, "Running post install script...");
|
|
360
369
|
try {
|
|
361
370
|
fs.chmodSync(postInstallPath, "0755");
|
|
362
|
-
|
|
371
|
+
const { stdout, stderr } = await exec(postInstallPath, {
|
|
363
372
|
cwd: plugin2.path,
|
|
364
373
|
shell: "bash"
|
|
365
374
|
});
|
|
@@ -545,6 +554,10 @@ async function init() {
|
|
|
545
554
|
}
|
|
546
555
|
function pluginLoaderFactory() {
|
|
547
556
|
const workDir = getWorkDir();
|
|
557
|
+
if (!workDir) {
|
|
558
|
+
err("Not an omegga directory, run ", "omegga init".yellow, "to setup one.");
|
|
559
|
+
process.exit(1);
|
|
560
|
+
}
|
|
548
561
|
return new plugin.PluginLoader(workDir);
|
|
549
562
|
}
|
|
550
563
|
async function loadPlugin(pluginName) {
|
|
@@ -559,12 +572,24 @@ async function loadPlugin(pluginName) {
|
|
|
559
572
|
const plugin2 = await pluginLoader.scanPlugin(
|
|
560
573
|
path.join(pluginLoader.path, foundPluginDirectory)
|
|
561
574
|
);
|
|
575
|
+
if (!plugin2) {
|
|
576
|
+
err(`Plugin ${pluginName} failed to load!`);
|
|
577
|
+
process.exit(1);
|
|
578
|
+
}
|
|
562
579
|
return plugin2;
|
|
563
580
|
}
|
|
581
|
+
function getConfigDoc(plugin2) {
|
|
582
|
+
const configDoc = plugin2.getDocumentation()?.config;
|
|
583
|
+
if (!configDoc) {
|
|
584
|
+
err("Plugin", plugin2.getName().cyan, "has no config documentation");
|
|
585
|
+
process.exit(1);
|
|
586
|
+
}
|
|
587
|
+
return configDoc;
|
|
588
|
+
}
|
|
564
589
|
async function listConfig(pluginName, json = false) {
|
|
565
590
|
const plugin2 = await loadPlugin(pluginName);
|
|
566
|
-
const configDoc = plugin2.getDocumentation()
|
|
567
|
-
const config2 = await plugin2.storage.getConfig();
|
|
591
|
+
const configDoc = plugin2.getDocumentation()?.config ?? {};
|
|
592
|
+
const config2 = await plugin2.storage.getConfig() ?? {};
|
|
568
593
|
if (json) {
|
|
569
594
|
console.log(JSON.stringify(config2, null, 2));
|
|
570
595
|
} else {
|
|
@@ -574,7 +599,7 @@ async function listConfig(pluginName, json = false) {
|
|
|
574
599
|
log(
|
|
575
600
|
key.cyan,
|
|
576
601
|
"=",
|
|
577
|
-
|
|
602
|
+
typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? value.toString().yellow : JSON.stringify(value).yellow
|
|
578
603
|
);
|
|
579
604
|
}
|
|
580
605
|
}
|
|
@@ -582,12 +607,12 @@ async function listConfig(pluginName, json = false) {
|
|
|
582
607
|
}
|
|
583
608
|
async function getConfig(pluginName, configName, json = false) {
|
|
584
609
|
const plugin2 = await loadPlugin(pluginName);
|
|
585
|
-
const configDoc = plugin2
|
|
610
|
+
const configDoc = getConfigDoc(plugin2)[configName];
|
|
586
611
|
if (configDoc === void 0) {
|
|
587
612
|
err("Config", configName.cyan, "not found");
|
|
588
613
|
process.exit(1);
|
|
589
614
|
}
|
|
590
|
-
const config2 = await plugin2.storage.getConfig();
|
|
615
|
+
const config2 = await plugin2.storage.getConfig() ?? {};
|
|
591
616
|
if (json) {
|
|
592
617
|
console.log(JSON.stringify(config2[configName], null, 2));
|
|
593
618
|
} else {
|
|
@@ -597,7 +622,7 @@ async function getConfig(pluginName, configName, json = false) {
|
|
|
597
622
|
}
|
|
598
623
|
async function setConfig(pluginName, configName, valueString) {
|
|
599
624
|
const plugin2 = await loadPlugin(pluginName);
|
|
600
|
-
const configDoc = plugin2
|
|
625
|
+
const configDoc = getConfigDoc(plugin2)[configName];
|
|
601
626
|
if (configDoc === void 0) {
|
|
602
627
|
err("Config", configName.cyan, "not found");
|
|
603
628
|
process.exit(1);
|
|
@@ -633,7 +658,7 @@ async function setConfig(pluginName, configName, valueString) {
|
|
|
633
658
|
err("set-context does not support config type", configDoc.type.cyan);
|
|
634
659
|
process.exit(1);
|
|
635
660
|
}
|
|
636
|
-
const pluginConfig = await plugin2.storage.getConfig();
|
|
661
|
+
const pluginConfig = await plugin2.storage.getConfig() ?? {};
|
|
637
662
|
pluginConfig[configName] = parsed;
|
|
638
663
|
await plugin2.storage.setConfig(pluginConfig);
|
|
639
664
|
log(
|
|
@@ -669,12 +694,12 @@ async function resetAllConfigs(pluginName, force) {
|
|
|
669
694
|
}
|
|
670
695
|
async function resetConfig(pluginName, configName) {
|
|
671
696
|
const plugin2 = await loadPlugin(pluginName);
|
|
672
|
-
const configDoc = plugin2
|
|
697
|
+
const configDoc = getConfigDoc(plugin2)[configName];
|
|
673
698
|
if (configDoc === void 0) {
|
|
674
699
|
err("Config", configName.cyan, "not found");
|
|
675
700
|
process.exit(1);
|
|
676
701
|
}
|
|
677
|
-
const pluginConfig = await plugin2.storage.getConfig();
|
|
702
|
+
const pluginConfig = await plugin2.storage.getConfig() ?? {};
|
|
678
703
|
pluginConfig[configName] = plugin2.storage.getDefaultConfig()[configName];
|
|
679
704
|
await plugin2.storage.setConfig(pluginConfig);
|
|
680
705
|
log(
|