omegga 1.13.0 → 1.14.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +103 -4
  3. package/dist/brickadia/server.js +8 -0
  4. package/dist/brickadia/server.js.map +1 -1
  5. package/dist/cli/auth.js +1 -1
  6. package/dist/cli/auth.js.map +1 -1
  7. package/dist/cli/plugin.js +4 -2
  8. package/dist/cli/plugin.js.map +1 -1
  9. package/dist/cli/terminal.js +48 -29
  10. package/dist/cli/terminal.js.map +1 -1
  11. package/dist/config/index.js +27 -1
  12. package/dist/config/index.js.map +1 -1
  13. package/dist/main.js +13 -4
  14. package/dist/main.js.map +1 -1
  15. package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js +1 -0
  16. package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js.map +1 -1
  17. package/dist/omegga/server.js +11 -4
  18. package/dist/omegga/server.js.map +1 -1
  19. package/dist/omegga/wrapper.js +4 -0
  20. package/dist/omegga/wrapper.js.map +1 -1
  21. package/dist/plugin.js.map +1 -1
  22. package/dist/util/container.js +10 -0
  23. package/dist/util/container.js.map +1 -0
  24. package/package.json +2 -2
  25. package/server/data/nedb-imported.marker +1 -0
  26. package/server/data/omegga-plugins.db +0 -0
  27. package/server/data/omegga-plugins.db-shm +0 -0
  28. package/server/data/omegga-plugins.db-wal +0 -0
  29. package/server/data/omegga-sessions.db +0 -0
  30. package/server/data/omegga-sessions.db-shm +0 -0
  31. package/server/data/omegga-sessions.db-wal +0 -0
  32. package/server/data/omegga.db +0 -0
  33. package/server/data/omegga.db-shm +0 -0
  34. package/server/data/omegga.db-wal +0 -0
  35. package/server/data/web_session_token +1 -0
  36. package/server/fakegame/Binaries/Linux/BrickadiaServer-Linux-Shipping +11 -0
  37. package/server/omegga-config.yml +7 -0
  38. package/templates/safe-ts/omegga.d.ts +19 -1
  39. package/tools/tag.sh +48 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Latest
4
4
 
5
+ ## 1.14.0 - 2026-08-28
6
+
7
+ - Add `omegga.binaryPath`: the directory containing the game server binary
8
+ - Fix Ctrl+C hanging Omegga in an endless `readline was closed` error loop instead of shutting down
9
+ - Fix terminal logs, launcher download progress, and plugin install progress crashing when stdout is not a TTY (piped output, `docker run` without `-t`)
10
+ - Pressing Ctrl+C a second time while shutting down force closes Omegga
11
+ - `OMEGGA_PORT` and `BRICKADIA_PORT` now override the ports in an existing config, not just when one is created
12
+ - Point the hosting token prompt at https://brickadia.com/account/tokens
13
+ - The update notice says to pull a new image when omegga is running in a container, instead of `npm i -g omegga`
14
+ - Add a `Dockerfile`: steamcmd base, node from nvm, runs unprivileged with PUID/PGID remapping; builds this repo by default, or `--target npm --build-arg OMEGGA_VERSION=x.y.z` for a release off npm
15
+ - CI: publish the image to `ghcr.io/brickadia-community/omegga` on `v*` tags (or manually), tagged by semver
16
+
5
17
  ## 1.13.0 - 2026-08-10
6
18
 
7
19
  - Add `server.remoteFiles` config (default `true`); when `false`, the server launches with `-NoRemoteFileAccess`
package/README.md CHANGED
@@ -40,6 +40,8 @@ Omegga plugins can do things like:
40
40
 
41
41
  You can run omegga in the [Windows Subsystem for Linux](#wsl) (I recommend Ubuntu) or on an actual linux install.
42
42
 
43
+ If you would rather not install node and omegga on the host, there is a [container image](#containers) that has both.
44
+
43
45
  <font size="5" color="red">Do not install omegga or run brickadia/omegga as root/superuser</font>:
44
46
 
45
47
  - running `whoami` should NOT print "root"
@@ -74,7 +76,7 @@ If you need to run omegga as root, make sure your branch is `main-server` or `un
74
76
  npm i -g omegga
75
77
  ```
76
78
 
77
- 4. Head over to [Running Omegga](#running) or troubleshoot below.
79
+ 4. Head over to [Running Omegga](#running) or troubleshoot below. To run it in a container instead of installing it, see [Containers](#containers).
78
80
 
79
81
  ### Install Troubleshooting
80
82
 
@@ -217,12 +219,109 @@ To start a server, simply type the following in a linux shell after install:
217
219
 
218
220
  Omegga will prompt for credentials as necessary and only stores the auth tokens brickadia generates on login. **Omegga does not store your password**.
219
221
 
222
+ ## Containers
223
+
224
+ Release tags publish an image to `ghcr.io/brickadia-community/omegga`.
225
+
226
+ ```sh
227
+ docker run -it --rm \
228
+ -v omegga-home:/home/steam \
229
+ -v "$PWD/server:/server" \
230
+ -p 8080:8080 -p 7777:7777/udp \
231
+ -e BRICKADIA_TOKEN -e OMEGGA_PORT=8080 -e BRICKADIA_PORT=7777 \
232
+ -e PUID="$(id -u)" -e PGID="$(id -g)" \
233
+ ghcr.io/brickadia-community/omegga
234
+ ```
235
+
236
+ 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.
237
+
238
+ Omegga is baked into the image, so it updates by pulling a new one rather than through npm:
239
+
240
+ ```sh
241
+ docker pull ghcr.io/brickadia-community/omegga:latest
242
+ docker compose pull && docker compose up -d # or, under compose
243
+ ```
244
+
245
+ `latest` moves with every release, so pin a version like `:1.14.0` if you would rather choose when that happens. Nothing pulls on its own - `podman auto-update` and watchtower are the usual ways to automate it.
246
+
247
+ The game is not in the image. It updates in place inside the volume with `omegga --update` or `/update`, and steamcmd keeps itself up to date. Setting the container's command to `omegga --update` (`command: omegga --update` under compose) checks on every start, at the cost of not starting at all when Steam is unreachable, rather than running the version already installed.
248
+
249
+ ### Compose
250
+
251
+ ```yaml
252
+ services:
253
+ omegga:
254
+ image: ghcr.io/brickadia-community/omegga:latest
255
+ restart: unless-stopped
256
+ stdin_open: true
257
+ tty: true
258
+ env_file: .env
259
+ ports:
260
+ - '${OMEGGA_PORT}:${OMEGGA_PORT}/tcp'
261
+ - '${BRICKADIA_PORT}:${BRICKADIA_PORT}/udp'
262
+ volumes:
263
+ - home:/home/steam
264
+ - ./server:/server
265
+
266
+ volumes:
267
+ home:
268
+ ```
269
+
270
+ ```sh
271
+ # .env - read for the ${...} above, and passed to the container
272
+ BRICKADIA_TOKEN=...
273
+ OMEGGA_PORT=8080
274
+ BRICKADIA_PORT=7777
275
+ PUID=1000
276
+ PGID=1000
277
+ ```
278
+
279
+ `compose run --rm --service-ports omegga` attaches a tty, so ctrl+c goes to omegga. With `compose up` it goes to compose, which stops the container instead.
280
+
281
+ ### Volumes
282
+
283
+ - `/home/steam` - the Brickadia install, steamcmd, and auth files. Keep it on a named volume or the game is downloaded again every time the container is recreated.
284
+ - `/server` - the omegga working directory: `omegga-config.yml`, `data`, and `plugins`. Bind mount it to edit them from the host.
285
+
286
+ ### Ports
287
+
288
+ Set them with `OMEGGA_PORT` and `BRICKADIA_PORT` rather than editing the config file, so one value drives both the server and the port mapping. They override the config, though `server.port` still has to be present in it. See [Environment Variables](#environment-variables) for the rest.
289
+
290
+ Brickadia reports its configured port to the master server, so a published port has to be the same number the server runs on. Never map `-p 7778:7777/udp`.
291
+
292
+ ### File Ownership
293
+
294
+ `PUID` and `PGID` decide who owns what omegga writes into a bind-mounted `/server`; set them to your own `id -u` and `id -g`. `PUID=0` runs as root instead and leaves root-owned files behind on the host.
295
+
296
+ ### Building
297
+
298
+ The `Dockerfile` builds omegga on top of `gameservermanagers/steamcmd`, with node from nvm.
299
+
300
+ ```sh
301
+ # the omegga in this checkout
302
+ docker build -t omegga .
303
+
304
+ # or a release off npm, where OMEGGA_VERSION is an npm version
305
+ docker build -t omegga --target npm --build-arg OMEGGA_VERSION=1.14.0 .
306
+ ```
307
+
308
+ `OMEGGA_VERSION` is required and has to be an exact version. There is deliberately no `latest` default: that layer is cached on its command text, so `latest` would never invalidate it - rebuilds would keep reinstalling whichever version was current the first time, and only `--no-cache` would get past it.
309
+
310
+ ### Podman
311
+
312
+ `podman build`, `podman run`, and `podman compose` take the same arguments and read the same compose file. Two things differ:
313
+
314
+ - Rootless podman maps the container's root to your own user, so `PUID=0` is what leaves bind-mounted files owned by you - the opposite of the advice above. Keeping the container's unprivileged user maps it to a subuid instead, and `/server` ends up owned by an id you need `podman unshare` to touch. To stay unprivileged inside the container, `--userns=keep-id:uid=1000,gid=1000` maps you onto the image's `steam` user.
315
+ - On SELinux systems bind mounts need a relabel: `-v "$PWD/server:/server:Z"`.
316
+
220
317
  ## Updating
221
318
 
222
319
  Omegga will tell you when it's out of date. You can update with this command:
223
320
 
224
321
  npm i -g omegga
225
322
 
323
+ In a container, pull a new image instead - see [Containers](#containers).
324
+
226
325
  If don't have automatic update enabled, you can start update the Brickadia server by starting omegga with the `--update` flag:
227
326
 
228
327
  omegga --update
@@ -1055,11 +1154,11 @@ These can be set in your shell or in a `.env` file the same directory as a `omeg
1055
1154
 
1056
1155
  `omegga` accepts the following environment variables:
1057
1156
 
1058
- - `BRICKADIA_TOKEN` - Specify hosting token instead of using config
1157
+ - `BRICKADIA_TOKEN` - Specify hosting token instead of using config (generate one at https://brickadia.com/account/tokens)
1059
1158
  - `BRICKADIA_USER` - Brickadia auth username (on first start)
1060
1159
  - `BRICKADIA_PASS` - Brickadia auth password (on first start)
1061
- - `BRICKADIA_PORT` - Brickadia server port (default `7777`, on config creation)
1062
- - `OMEGGA_PORT` - omegga webserver port (default `8080`, on config creation)
1160
+ - `BRICKADIA_PORT` - Brickadia server port (default `7777`); overrides `server.port` from the config
1161
+ - `OMEGGA_PORT` - omegga webserver port (default `8080`); overrides `omegga.port` from the config
1063
1162
  - `OMEGGA_UI_HOST` - host shown in the "Web UI available at" log message (default `127.0.0.1`)
1064
1163
  - `BRICKADIA_DIR` - Override the need to use steamcmd and point to a Brickadia install directory (eg. `/home/<USER>/.config/omegga/steam_installs/main/Brickadia`)
1065
1164
  - `STEAM_INSTALLS_DIR` - Set where omegga installs brickadia via steamcmd (default `~/.config/omegga/steam_installs`)
@@ -134,6 +134,14 @@ class BrickadiaServer extends EventEmitter {
134
134
  // path to binary
135
135
  );
136
136
  }
137
+ /**
138
+ * Resolve the directory the game server binary lives in. Null whenever
139
+ * {@link getGameBinaryPath} can't resolve a binary.
140
+ */
141
+ getGameBinaryDir() {
142
+ const binary = this.getGameBinaryPath();
143
+ return binary && path.dirname(binary);
144
+ }
137
145
  // start the server child process
138
146
  start() {
139
147
  const {
@@ -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 { 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":";;;;;;;;;;;;;;AA2BA,MAAM,cAKA;AAAA,EACJ;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OACE;AAAA,EAAA;AAAA,EAEJ;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OACE;AAAA,EAAA;AAEN;AAGA,MAAqB,wBAAwB,aAAa;AAAA,EACxD,SAAgD;AAAA,EAChD,gBAA2C;AAAA,EAC3C,gBAA2C;AAAA,EAK3C,YAAY,UAAkB,QAAiB;AAC7C,UAAA;AAEA,SAAK,SAAS;AAEd,SAAK,OACH,KAAK,WAAW,QAAQ,KAAK,SAAS,WAAW,GAAG,IAChD,WACA,KAAK,KAAK,QAAQ,IAAA,GAAO,QAAQ;AAEvC,SAAK,eAAe,KAAK,aAAa,KAAK,IAAI;AAC/C,SAAK,gBAAgB,KAAK,cAAc,KAAK,IAAI;AACjD,SAAK,eAAe,KAAK,aAAa,KAAK,IAAI;AAAA,EACjD;AAAA,EAEA,qBAA6B;AAC3B,WAAO,KAAK,KAAK,KAAK,MAAMA,WAAAA,iBAAiB;AAAA,EAC/C;AAAA;AAAA,EAGA,iBAAgC;AAC9B,UAAM,kBAAkB,KAAK,mBAAA;AAC7B,QAAIC,GAAAA,WAAW,eAAe,GAAG;AAC/B,UAAI;AACF,eAAOC,gBAAa,iBAAiB,MAAM,EAAE,KAAA;AAAA,MAC/C,SAAS,KAAK;AACZC,eAAAA,QAAO;AAAA,UACL;AAAA,UACA,gBAAgB;AAAA,UAChB;AAAA,QAAA;AAEF,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,eAAe,OAA+B;AAC5C,UAAM,kBAAkB,KAAK,mBAAA;AAC7B,QAAI,CAAC,SAAS,UAAU,MAAM;AAC5B,UAAIF,GAAAA,WAAW,eAAe,GAAG;AAC/BE,eAAAA,QAAO,QAAQ,8BAA8B,gBAAgB,MAAM;AACnEC,WAAAA,WAAW,eAAe;AAAA,MAC5B;AACA,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,KAAK,YAAY,KAAK,GAAG;AAC5BD,aAAAA,QAAO;AAAA,QACL;AAAA,QACA,MAAM;AAAA,QACN;AAAA,MAAA;AAEF,aAAO;AAAA,IACT;AAEAA,WAAAA,QAAO,QAAQ,2BAA2B,MAAM,MAAM;AACtD,QAAI;AACFE,uBAAc,iBAAiB,OAAO,MAAM;AAC5C,aAAO;AAAA,IACT,SAAS,KAAK;AACZF,aAAAA,QAAO;AAAA,QACL;AAAA,QACA,gBAAgB;AAAA,QAChB;AAAA,MAAA;AAEF,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,iBAAgC;AAC9B,WAAO,KAAK,QAAQ,QAAQ,SAAS;AAAA,EACvC;AAAA;AAAA,EAGA,cAA6B;AAC3B,WAAOG,aAAAA,IAAI,mBAAmB;AAAA,EAChC;AAAA;AAAA,EAGA,YAAY,OAAwB;AAClC,UAAM,WAAW,KAAK,QAAQ,QAAQ,YAAYC,WAAAA;AAClD,UAAM,YAAY,KAAK,KAAK,KAAK,MAAM,UAAU,UAAU,QAAQ,OAAO;AAC1E,WAAON,GAAAA,WAAW,SAAS;AAAA,EAC7B;AAAA;AAAA,EAGA,eAAwD;AACtD,UAAM,aAAa;AAAA,MACjB,EAAE,QAAQ,QAAQ,MAAM,KAAK,iBAAe;AAAA,MAC5C,EAAE,QAAQ,UAAU,MAAM,KAAK,iBAAe;AAAA,MAC9C,EAAE,QAAQ,OAAO,MAAM,KAAK,cAAY;AAAA,IAAE;AAG5C,WACE,WAAW;AAAA,MACT,CAAC,MACC,CAAC,CAAC,EAAE,QAAQ,KAAK,YAAY,EAAE,IAAI;AAAA,IAAA,KAClC;AAAA,EAET;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAmC;AACjC,UAAM,iBAAiBO,WAAAA,sBAAA;AACvB,QAAI,eAAgB,QAAO;AAG3B,UAAM,UAAU,CAAC,KAAK,OAAO,OAAO;AACpC,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,YAAY,KAAK,OAAO,OAAO,aAAa;AAClD,WAAO,KAAK;AAAA,MACVC,8BAAA;AAAA;AAAA,MACA;AAAA;AAAA,MACAC,2BAAA;AAAA;AAAA,MACAC,WAAAA;AAAAA;AAAAA,IAAA;AAAA,EAEJ;AAAA;AAAA,EAGA,QAAQ;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IAAA,IACkD,KAAK,OAC7D,eAAe,CAAA;AAElB,UAAM,QAAQ,aAAa,QAAQ,IAAI,mBAAmBC,KAAAA,eAAA;AAE1D,QAAI,OAAO;AACTT,aAAAA,QAAO,QAAQ,oCAAoC;AAAA,IACrD,OAAO;AACLA,aAAAA,QAAO;AAAA,QACL;AAAA,SACC,CAAC,SAAS,CAAC,WAAW,YAAY,QAAQ;AAAA,QAC3C;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAM,UAAU,CAAC,KAAK,OAAO,OAAO;AACpC,UAAM,YAAY,KAAK,OAAO,OAAO,aAAa;AAClD,UAAM,iBAAiBK,WAAAA,sBAAA;AACvB,UAAM,cAAc,KAAK;AAAA,MACvBC,8BAAA;AAAA;AAAA,MACA;AAAA;AAAA,MACAC,2BAAA;AAAA;AAAA,MACAC,WAAAA;AAAAA;AAAAA,IAAA;AAGF,QAAI,aAAa,KAAK,kBAAA,KAAuB;AAE7C,QAAI,gBAAgB;AAClB,UAAI,CAACV,GAAAA,WAAW,cAAc,GAAG;AAC/BE,eAAAA,QAAO;AAAA,UACL;AAAA,UACA,eAAe;AAAA,UACf;AAAA,QAAA;AAEF,cAAM,IAAI,MAAM,mBAAmB,cAAc,kBAAkB;AAAA,MACrE;AAEAA,aAAAA,QAAO;AAAA,QACL;AAAA,QACA,eAAe;AAAA,QACf;AAAA,QACA,YAAY;AAAA,MAAA;AAEd,mBAAa;AAAA,IACf,WAAW,SAAS;AAClBA,aAAAA,QAAO,QAAQ,sBAAsB,UAAU,MAAM;AAAA,IACvD,OAAO;AACLA,aAAAA,QAAO;AAAA,QACL;AAAA,SACC,KAAK,OAAO,OAAO,UAChB,KAAK,KAAK,WAAW,0BAA0B,IAC/C,sBACF;AAAA,MAAA;AAEJ,UAAI,OAAO,KAAK,OAAO,OAAO,WAAW;AACvCA,eAAAA,QAAO,QAAQ,gBAAgB,KAAK,OAAO,OAAO,OAAO,MAAM;AAAA,IACnE;AAGA,UAAM,aAAa,UACf,CAAC,UAAU,IACX;AAAA,MACE,KAAK,OAAO,OAAO,UACf,KAAK,KAAK,WAAW,0BAA0B,IAC/C;AAAA,MACJ,KAAK,OAAO,OAAO,UAAU,YAAY,KAAK,OAAO,OAAO,MAAM;AAAA,MAClE;AAAA,MACA;AAAA,IAAA;AAGN,UAAM,QAAQ,KAAK,aAAA;AACnB,QAAI,OAAO;AACTA,aAAAA,QAAO;AAAA,QACL;AAAA,QACA,MAAM,KAAK;AAAA,QACX;AAAA,QACA,MAAM,OAAO;AAAA,MAAA;AAAA,IAEjB,WAAW,KAAK,OAAO,OAAO,KAAK;AACjCA,qBAAO,QAAQ,aAAa,KAAK,OAAO,OAAO,IAAI,QAAQ,aAAa;AAAA,IAC1E;AAEA,UAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH,CAAC,SACC,KAAK,OAAO,OAAO,OACnB,iBAAiB,KAAK,OAAO,OAAO,GAAG;AAAA,MACzC,SAAS,WAAW,MAAM,IAAI;AAAA,MAC9B;AAAA,MACA;AAAA;AAAA,MAEA,KAAK,OAAO,OAAO,gBAAgB,QAAQ,wBAAwB;AAAA,MACnEU,aAAA,MAAe,IAAI,eAAe;AAAA,MAClC,KAAK,OAAO,aAAa,KAAK,IAAI,MAAM;AAAA,MACxC,QAAQ,WAAW,KAAK,MAAM;AAAA;AAAA,MAC9B,CAAC,SAAS,QAAQ,UAAU,KAAK,MAAM;AAAA;AAAA,MACvC,CAAC,SAAS,WAAW,cAAc,QAAQ,MAAM;AAAA;AAAA,MACjD,UAAU,KAAK,OAAO,OAAO,IAAI;AAAA,MACjC,KAAK,OAAO,OAAO;AAAA,IAAA,EAElB,OAAO,CAAA,QAAO,OAAO,QAAQ,QAAQ,EACrC,OAAO,CAAA,QAAO,IAAI,SAAS,CAAC;AAC/BV,WAAAA,QAAO;AAAA,MACL;AAAA,MACA,OACG,KAAK,GAAG,EACR,QAAQ,eAAe,kBAAkB,EACzC,QAAQ,mBAAmB,sBAAsB,EACjD,QAAQ,gBAAgB,mBAAmB,EAC3C,QAAQ,iBAAiB,oBAAoB,EAC7C,QAAQ,eAAe,kBAAkB;AAAA,IAAA;AAM9C,UAAM,QAAQW,mBAAAA,MAAM,UAAU,MAAM;AACpC,SAAK,SAAS;AAEdX,WAAAA,QAAO,QAAQ,iBAAiB,MAAM,OAAO,SAAS,GAAG;AAEzD,UAAM,MAAM,mBAAmB,MAAM;AACrC,SAAK,gBAAgB,SAAS,gBAAgB;AAAA,MAC5C,OAAO,MAAM;AAAA,MACb,UAAU;AAAA,IAAA,CACX;AACD,SAAK,gBAAgB,SAAS,gBAAgB;AAAA,MAC5C,OAAO,MAAM;AAAA,MACb,UAAU;AAAA,IAAA,CACX;AACD,SAAK,gBAAA;AACLA,WAAAA,QAAO,QAAQ,oBAAoB;AAAA,EACrC;AAAA;AAAA,EAGA,MAAM,MAAc;AAClB,QAAI,KAAK,UAAU,KAAK;AAEtBA,aAAAA,QAAO;AAAA,QACL,UAAU;AAAA,QACV;AAAA,QACA,4BAA4B;AAAA,MAAA;AAE9BA,aAAAA,QAAO,KAAK,KAAK,QAAQ,OAAO,EAAE,CAAC;AAEnC,UAAI;AACF,cAAM,IAAI,MAAM,uBAAuB;AAAA,MACzC,SAAS,KAAK;AACZA,eAAAA,QAAO,KAAK,GAAG;AAAA,MACjB;AACA;AAAA,IACF;AACA,QAAI,KAAK,QAAQ;AACfA,qBAAO,QAAQ,QAAQ,OAAO,KAAK,QAAQ,OAAO,EAAE,CAAC;AACrD,WAAK,OAAO,MAAM,MAAM,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA,EAGA,QAAQ,MAAc;AACpB,SAAK,MAAM,OAAO,IAAI;AAAA,EACxB;AAAA;AAAA,EAGA,OAAO;AACL,QAAI,CAAC,KAAK,QAAQ;AAChBA,aAAAA,QAAO,QAAQ,4CAA4C;AAC3D;AAAA,IACF;AAEAA,WAAAA,QAAO,QAAQ,0BAA0B;AAEzC,SAAK,OAAO,KAAK,QAAQ;AAGzBW,uBAAAA,MAAM,QAAQ,CAAC,MAAM,KAAK,OAAO,MAAM,EAAE,CAAC;AAAA,EAC5C;AAAA;AAAA,EAGA,UAAU;AACR,QAAI,CAAC,KAAK,OAAQ;AAElBX,WAAAA,QAAO,QAAQ,8BAA8B;AAG7C,SAAK,gBAAA;AAEL,SAAK,SAAS;AACd,SAAK,gBAAgB;AACrB,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAGA,kBAAkB;AAChB,SAAK,eAAe,GAAG,QAAQ,KAAK,YAAY;AAChD,SAAK,eAAe,GAAG,QAAQ,KAAK,aAAa;AACjD,SAAK,QAAQ,GAAG,QAAQ,KAAK,YAAY;AACzC,SAAK,QAAQ,GAAG,SAAS,MAAM;AAAA,IAAC,CAAC;AAAA,EACnC;AAAA;AAAA,EAGA,kBAAkB;AAChB,SAAK,eAAe,IAAI,QAAQ,KAAK,YAAY;AACjD,SAAK,eAAe,IAAI,QAAQ,KAAK,aAAa;AAClD,SAAK,QAAQ,IAAI,QAAQ,KAAK,YAAY;AAC1C,SAAK,QAAQ,mBAAmB,OAAO;AAAA,EACzC;AAAA;AAAA,EAGA,cAAc,MAAc;AAC1BA,WAAAA,QAAO,QAAQ,QAAQ,KAAK,IAAI;AAChC,SAAK,KAAK,OAAO,IAAI;AACrB,eAAW,EAAE,OAAO,UAAU,MAAM,QAAA,KAAa,aAAa;AAC5D,UAAI,KAAK,MAAM,KAAK,GAAG;AACrBA,eAAAA,QAAO;AAAA,UACL,eAAe,KAAK,GAAG,KACrB,WAAW,mBAAmB,WAAW,WAAW,gBACtD;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF;AAAA,EACF;AAAA,EAEA,gBAAgB,MAAa;AAC3BA,WAAAA,QAAO,QAAQ,qBAAqB;AACpC,SAAK,KAAK,UAAU,GAAG,IAAI;AAC3B,SAAK,QAAA;AAAA,EACP;AAAA,EAEA,aAAa,MAAc;AACzB,SAAK,KAAK,QAAQ,UAAU,IAAI,CAAC;AAAA,EACnC;AACF;;"}
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 /**\n * Resolve the directory the game server binary lives in. Null whenever\n * {@link getGameBinaryPath} can't resolve a binary.\n */\n getGameBinaryDir(): string | null {\n const binary = this.getGameBinaryPath();\n return binary && path.dirname(binary);\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
@@ -58,7 +58,7 @@ async function authFromPrompt({
58
58
  const { token } = await prompts({
59
59
  type: "password",
60
60
  name: "token",
61
- message: "Paste your server hosting token (from https://brickadia.com/account)",
61
+ message: "Paste your server hosting token (generate one at https://brickadia.com/account/tokens)",
62
62
  validate: (value) => value ? true : "Token is required"
63
63
  });
64
64
  if (!token) {
@@ -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 (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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"}
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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"}
@@ -53,8 +53,10 @@ const transformUrl = (url) => {
53
53
  };
54
54
  let needsNL = false;
55
55
  const rewriteLine = (...args) => {
56
- process.stdout.clearLine(0);
57
- process.stdout.cursorTo(0);
56
+ if (process.stdout.isTTY) {
57
+ process.stdout.clearLine(0);
58
+ process.stdout.cursorTo(0);
59
+ }
58
60
  process.stdout.write(args.join(" "));
59
61
  needsNL = true;
60
62
  };
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../src/cli/plugin.ts"],"sourcesContent":["import Logger from '@/logger';\nimport soft from '@/softconfig';\nimport * as config from '@config';\nimport { PluginLoader } from '@omegga/plugin';\nimport { exec as execNonPromise } from 'node:child_process';\nimport 'colors';\nimport fs from 'node:fs';\nimport hasbin from 'hasbin';\nimport path from 'node:path';\nimport prompts from 'prompts';\nimport semver from 'semver';\nimport simpleGit, {\n ResetMode,\n type SimpleGit,\n type StatusResult,\n} from 'simple-git';\nimport { promisify } from 'node:util';\nimport { VERSION } from '@/version';\n\nconst exec = promisify(execNonPromise);\n\nconst MAIN_BRANCHES = ['master', 'main'];\n\n// get the working directory for omegga\nfunction getWorkDir() {\n // default working directory is the one specified in config\n let workDir = config.store.get('defaultOmegga');\n verboseLog('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 const confFile = config.find(workDir);\n\n return confFile\n ? path.resolve(process.cwd(), path.dirname(confFile))\n : undefined;\n}\n\ninterface IPlugin {\n name?: string;\n type: string | 'raw';\n url: string;\n}\n\ninterface IInstalledPlugin {\n name: string;\n path?: string;\n git?: SimpleGit;\n}\n\ninterface ITransformer {\n pattern: RegExp;\n fn(match: Record<string, string>): IPlugin;\n}\n\nconst PLUGIN_TYPES = ['safe', 'safe-ts', 'unsafe', 'rust', 'rpc'];\ntype PluginType = (typeof PLUGIN_TYPES)[number];\n\n// plugin url transformers\nconst transformers: ITransformer[] = [\n {\n // github transformer\n pattern: /^gh:(?<owner>[^/]+)\\/(?<repo>[^/]+)$/,\n fn: ({ owner, repo }) => ({\n type: 'short',\n name: repo,\n url: `https://github.com/${owner}/omegga-${repo}`,\n }),\n },\n {\n // gitlab transformer\n pattern: /^gl:(?<owner>[^/]+)\\/(?<repo>[^/]+)$/,\n fn: ({ owner, repo }) => ({\n type: 'short',\n name: repo,\n url: `https://gitlab.com/${owner}/omegga-${repo}`,\n }),\n },\n];\n\n// convert a shortened url into a full length one\nconst transformUrl = (url: string): IPlugin => {\n for (const t of transformers) {\n const match = url.match(t.pattern);\n if (match?.groups) return t.fn(match.groups);\n }\n return { type: 'raw', url };\n};\n\nlet needsNL = false;\n\n// rewrite a console line\nconst rewriteLine = (...args: string[]) => {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n process.stdout.write(args.join(' '));\n needsNL = true;\n};\n\n// logging helper functions\nconst plg = (plugin: IPlugin | IInstalledPlugin, ...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.log();\n }\n console.log(plugin.name, '>>'.green, ...args);\n};\nconst plgLog = (plugin: IPlugin | IInstalledPlugin, ...args: any[]) => {\n if (Logger.VERBOSE) plg(plugin, ...args);\n else\n rewriteLine(\n plugin.name ?? ('url' in plugin ? plugin.url : ''),\n '>>'.green,\n ...args,\n );\n};\nconst plgWarn = (plugin: IPlugin | IInstalledPlugin, ...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.warn();\n }\n console.warn(plugin.name, 'W>'.yellow, ...args);\n};\nconst plgErr = (plugin: IPlugin | IInstalledPlugin, ...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.error();\n }\n console.error(plugin.name, '!>'.red, ...args);\n};\n\nconst err = (...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.error();\n }\n console.error('!>'.red, ...args);\n};\nconst log = (...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.log();\n }\n console.log('>>'.green, ...args);\n};\nconst verboseLog = (...args: any[]) => {\n if (!Logger.VERBOSE) return;\n if (needsNL) {\n needsNL = false;\n console.log();\n }\n console.log('V>'.magenta, ...args);\n};\n\nfunction checkPlugin(\n omeggaPath: string,\n plugin: (IPlugin & { name: string }) | IInstalledPlugin,\n) {\n const pluginPath = path.join(omeggaPath, soft.PLUGIN_PATH, plugin.name);\n\n // check for the plugin file, whatever it's called\n if (fs.existsSync(path.join(pluginPath, soft.PLUGIN_FILE))) {\n if (needsNL) {\n console.log();\n needsNL = false;\n }\n plgLog(plugin, 'Checking plugin file...');\n let data;\n try {\n data = JSON.parse(\n fs.readFileSync(path.join(pluginPath, soft.PLUGIN_FILE), 'utf8'),\n );\n } catch (e) {\n plgErr(plugin, 'Error reading plugin file', e);\n return false;\n }\n\n // make sure this plugin version is okay.\n // in the future, this may include deprecation warnings and format changes\n if (data.formatVersion !== 1) {\n plgWarn(\n plugin,\n 'WARNING - Plugin file has invalid',\n 'formatVersion'.yellow + '. Expected',\n '1'.yellow,\n );\n return;\n }\n\n // check the omeggaVersion field of the plugin file\n if (!data.omeggaVersion || !semver.validRange(data.omeggaVersion)) {\n plgWarn(\n plugin,\n 'WARNING - Plugin file has invalid',\n 'omeggaVersion'.yellow + '. Expected semver expression',\n );\n return false;\n } else if (!semver.satisfies(VERSION, data.omeggaVersion)) {\n plgWarn(\n plugin,\n `WARNING - Plugin is not made for this version of omegga (${VERSION.yellow} vs ${data.omeggaVersion.yellow})`,\n );\n return false;\n }\n\n plgLog(plugin, 'Plugin file', 'OK'.green);\n return true;\n }\n\n // no plugin file, no problem!\n plgWarn(\n plugin,\n `WARNING - Plugin is missing plugin file (${soft.PLUGIN_FILE}), this may be a problem in future versions`,\n );\n return true;\n}\n\n// install plugins from a list of plugins\nexport async function install(plugins: string[], _options: unknown) {\n const omeggaPath = getWorkDir();\n if (!omeggaPath)\n return err(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n\n log('Attempting to install', (plugins.length + '').yellow, 'plugins...');\n\n for (const pluginUrl of plugins) {\n const transformed = transformUrl(pluginUrl);\n\n // if the plugin wasn't transformed, try to extract its name from the git url\n let name = transformed.name;\n if (!name) {\n try {\n name = path.parse(transformed.url).name.replace(/^omegga-/, '');\n } catch (e) {\n console.error('!>'.red, 'Error parsing name from url', transformed.url);\n break;\n }\n }\n const plugin = { ...transformed, name };\n\n log(\n 'Installing plugin',\n plugin.name.yellow,\n 'from',\n plugin.url.yellow + '...',\n );\n\n // plugin absolute path\n const pluginPath = path.join(omeggaPath, soft.PLUGIN_PATH, plugin.name);\n\n // check if plugin already exists\n // TODO: if force is passed in, remove the old directory\n if (\n fs.existsSync(pluginPath) &&\n fs.existsSync(path.join(pluginPath, 'doc.json'))\n ) {\n plgErr(\n plugin,\n 'Directory already exists! Try',\n ('omegga update ' + plugin.name).yellow,\n 'or check for plugin name collisions',\n );\n continue;\n }\n\n if (!fs.existsSync(pluginPath)) {\n // create plugin local directory\n try {\n fs.mkdirSync(pluginPath, { recursive: true });\n } catch (e) {\n plgErr(plugin, 'Error creating plugin directory', e);\n }\n }\n\n // clone the plugin from git\n try {\n plgLog(plugin, 'Cloning...');\n const git = simpleGit(pluginPath);\n await git.clone(plugin.url, pluginPath);\n } catch (e) {\n plgErr(plugin, 'Error cloning plugin', e);\n }\n\n // check for the plugin file for issues\n // TODO: if force is passed in, ignore the plugin check\n if (!checkPlugin(omeggaPath, plugin)) continue;\n\n const postInstallPath = path.join(pluginPath, soft.PLUGIN_POSTINSTALL);\n if (fs.existsSync(postInstallPath)) {\n plgLog(plugin, 'Running post install script...');\n try {\n verboseLog('Changing permission of', postInstallPath);\n fs.chmodSync(postInstallPath, '0755');\n verboseLog('Executing bash file');\n const { stdout, stderr } = await exec(postInstallPath, {\n cwd: pluginPath,\n shell: 'bash',\n });\n\n if (stderr.length) plgErr(plugin, stderr);\n\n verboseLog(stdout);\n } catch (e) {\n plgErr(plugin, 'Error running post install script:', e);\n }\n }\n }\n}\nexport async function update(pluginsNames: string[], _options: unknown) {\n const omeggaPath = getWorkDir();\n if (!omeggaPath)\n return err(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n\n const pluginFolder = path.join(omeggaPath, soft.PLUGIN_PATH);\n\n // if no plugins are passed in, use every plugin in the plugins folder\n if (pluginsNames.length === 0) {\n pluginsNames = fs.readdirSync(pluginFolder);\n }\n\n const plugins: IInstalledPlugin[] = pluginsNames\n .map(dir => path.join(pluginFolder, dir))\n // every plugin must be in a directory\n .filter(\n dir =>\n fs.existsSync(dir) &&\n fs.lstatSync(dir).isDirectory() &&\n fs.existsSync(path.join(dir, '.git')),\n )\n .map(dir => ({ name: path.basename(dir) }));\n\n if (plugins.length === 0) {\n log('Found no plugins that can be updated');\n return;\n }\n\n log('Checking', (plugins.length + '').yellow, 'plugins for updates...');\n\n // list of plugins that will be updated\n const pluginsToUpdate: (IInstalledPlugin & {\n path: string;\n git: SimpleGit;\n })[] = [];\n\n for (const plugin of plugins) {\n if (needsNL) {\n console.log();\n needsNL = false;\n }\n plgLog(plugin, 'Checking...');\n const pluginPath = path.join(pluginFolder, plugin.name);\n plugin.path = pluginPath;\n const git = simpleGit(pluginPath);\n plugin.git = git;\n if (!(await git.checkIsRepo())) {\n plgErr(plugin, 'No git repo detected');\n continue;\n }\n\n let status: StatusResult;\n // get git status\n try {\n status = await git.status();\n } catch (e) {\n plgErr(plugin, 'Error getting status', e);\n continue;\n }\n\n try {\n // check for uncommitted changes\n if (status.files.some(f => f.working_dir !== '?')) {\n plgErr(plugin, 'Detected uncommitted changes - ignoring');\n continue;\n }\n\n const remotes = await git.getRemotes();\n const branches = await git.branch();\n\n // check if we're on a weird branch\n if (!MAIN_BRANCHES.includes(branches.current)) {\n plgErr(plugin, 'Not on a main branch - ignoring');\n continue;\n }\n\n // try to correct a weird detached branch\n if (\n remotes.length === 1 &&\n remotes[0].name === 'origin' &&\n !status.tracking\n ) {\n let skip = false;\n for (const branch of MAIN_BRANCHES) {\n if (\n branches.current === branch &&\n branches.branches[`remotes/origin/${branch}`]\n ) {\n plgLog(plugin, 'Correcting upstream...');\n try {\n await git.branch({ '--set-upstream-to': `origin/${branch}` });\n status = await git.status();\n break;\n } catch (e) {\n plgErr(plugin, 'Error getting status/fixing upstream branch', e);\n skip = true;\n break;\n }\n }\n }\n if (skip) continue;\n }\n\n // this should be corrected by the above check, though if it's not I am not fighting git lol\n if (!status.tracking) {\n plgErr(plugin, 'No upstream branch - ignoring');\n continue;\n }\n\n // local developers, publish your code please!!! :)\n if (remotes.length === 0) {\n plgErr(plugin, 'No remotes - ignoring');\n continue;\n }\n\n try {\n plgLog(plugin, 'Fetching...');\n await git.fetch();\n status = await git.status();\n } catch (e) {\n plgErr(plugin, 'Error fetching remote code', e);\n continue;\n }\n\n if (status.ahead > 0) {\n plgErr(plugin, 'Detected plugin is ahead - ignoring');\n continue;\n }\n\n if (status.behind === 0) {\n plgLog(plugin, 'Already up-to-date!'.green);\n continue;\n }\n\n plgLog(plugin, 'Update available');\n pluginsToUpdate.push({ ...plugin, path: pluginPath, git });\n } catch (e) {\n plgErr(plugin, 'Error', e);\n }\n }\n\n if (pluginsToUpdate.length === 0) {\n log('All plugins are currently up-to-date');\n return;\n }\n\n log('Updating', (pluginsToUpdate.length + '').yellow, 'plugins...');\n let updates = 0;\n\n for (const plugin of pluginsToUpdate) {\n const { git } = plugin;\n if (needsNL) {\n console.log();\n needsNL = false;\n }\n plgLog(plugin, 'Creating backup branch...');\n try {\n const branches = await git.branch();\n const mainBranch =\n MAIN_BRANCHES.find(b => branches.branches[b]) ?? MAIN_BRANCHES[0];\n if (branches.branches['omegga-upgrade-backup']) {\n plgLog(plugin, 'Deleting leftover backup branch...');\n await git.deleteLocalBranch('omegga-upgrade-backup', true);\n }\n await git.checkoutBranch('omegga-upgrade-backup', mainBranch);\n await git.branch({ '--set-upstream-to': `origin/${mainBranch}` });\n await git.checkout(mainBranch);\n plgLog(plugin, 'Pulling update...');\n await git.pull();\n if ((await git.status()).behind > 0) {\n throw '- still behind?';\n }\n plgLog(plugin, 'Checking plugin versions...');\n if (!checkPlugin(omeggaPath, plugin)) {\n throw 'Incompatible';\n }\n\n const postInstallPath = path.join(plugin.path, soft.PLUGIN_POSTINSTALL);\n if (fs.existsSync(postInstallPath)) {\n plgLog(plugin, 'Running post install script...');\n try {\n fs.chmodSync(postInstallPath, '0755');\n const { stdout, stderr } = await exec(postInstallPath, {\n cwd: plugin.path,\n shell: 'bash',\n });\n\n if (stderr.length) plgErr(plugin, stderr);\n\n verboseLog(stdout);\n } catch (e) {\n plgErr(plugin, 'Error running post install script:', e);\n }\n }\n\n plgLog(plugin, 'Updated!'.green);\n updates++;\n } catch (e) {\n plgErr(\n plugin,\n 'Error updating - attempting to restore from backup branch',\n e,\n );\n try {\n const branches = await git.branch();\n if (!MAIN_BRANCHES.includes(branches.current)) {\n plgErr(\n plugin,\n 'Not on expected branch - exiting before I break more things',\n );\n continue;\n }\n\n const mainBranch =\n MAIN_BRANCHES.find(b => branches.branches[b]) ?? MAIN_BRANCHES[0];\n\n plg(plugin, 'Resetting current branch');\n await git.reset(ResetMode.HARD);\n plgLog(plugin, 'Attempting to checkout backup branch');\n await git.checkout('omegga-upgrade-backup');\n plgLog(plugin, `Replacing ${mainBranch} with backup`);\n await git.deleteLocalBranch(mainBranch);\n await git.checkoutBranch(mainBranch, 'omegga-upgrade-backup');\n plgLog(plugin, 'Restored to backup branch');\n\n if ((await git.branch()).current !== mainBranch) {\n plgErr(\n plugin,\n `Failed to checkout newly created ${mainBranch} branch`,\n );\n continue;\n } else {\n plgWarn(plugin, 'Restored from backup and plugin not updated...');\n }\n } catch (e) {\n plgErr(plugin, 'Error restoring from backup... Whelp...');\n }\n continue;\n }\n }\n\n log('Updated', (updates + '').yellow, 'plugins!');\n}\n\nexport async function check(pluginNames: string[], _options: unknown) {\n const omeggaPath = getWorkDir();\n if (!omeggaPath)\n return err(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n\n const pluginFolder = path.join(omeggaPath, soft.PLUGIN_PATH);\n\n // if no plugins are passed in, use every plugin in the plugins folder\n if (pluginNames.length === 0) {\n pluginNames = fs.readdirSync(pluginFolder);\n }\n\n const plugins: IInstalledPlugin[] = pluginNames\n .map(dir => path.join(pluginFolder, dir))\n // every plugin must be in a directory\n .filter(\n dir =>\n fs.existsSync(dir) &&\n fs.lstatSync(dir).isDirectory() &&\n fs.existsSync(path.join(dir, '.git')),\n )\n .map(dir => ({ name: path.basename(dir) }));\n\n if (plugins.length === 0) {\n log('Found no plugins that can be checked');\n return;\n }\n\n log(\n 'Checking',\n (plugins.length + '').yellow,\n 'plugins for valid plugin files',\n );\n\n for (const plugin of plugins) {\n const pluginPath = path.join(pluginFolder, plugin.name);\n plugin.path = pluginPath;\n const git = simpleGit(pluginPath);\n plugin.git = git;\n if (!(await git.checkIsRepo())) {\n plgErr(plugin, 'No git repo detected');\n continue;\n }\n checkPlugin(omeggaPath, plugin);\n }\n console.log();\n}\n\nconst EXECUTABLES = ['setup.sh', 'omegga_plugin'];\n\nasync function init() {\n const { author, ...response } = await prompts([\n {\n type: 'text',\n name: 'name',\n message: 'What would you like to ' + 'name'.yellow + ' your plugin?',\n validate: value =>\n value.match(/^[\\w-_]+$/) ? true : 'Invalid plugin name!',\n },\n {\n type: 'select',\n name: 'type',\n message:\n 'What ' + 'type'.yellow + ' of plugin would you like to initialize?',\n choices: [\n { title: 'safe ' + '(default)'.italic, value: 'safe' },\n { title: 'unsafe', value: 'unsafe' },\n { title: 'rust', value: 'rust' },\n { title: 'rpc', value: 'rpc' },\n ],\n },\n {\n type: prev => (prev == 'safe' ? 'confirm' : null),\n name: 'ts',\n message:\n 'Would you like to use ' + 'TypeScript'.yellow + ' in your plugin?',\n initial: false,\n },\n {\n type: 'text',\n name: 'author',\n message: 'Who is the ' + 'author'.yellow + ' of this plugin?',\n },\n ]);\n\n const name = response.name;\n const type: PluginType =\n response.type == 'safe' && response.ts ? 'safe-ts' : response.type;\n\n if (!PLUGIN_TYPES.includes(type)) {\n err('Invalid plugin type', type.red, '!');\n process.exit(1);\n }\n\n let dest: string;\n if (!config.find('.')) {\n log(\n 'Warning:'.yellow,\n 'This is not an omegga installation, initializing here instead...',\n );\n dest = `./${name}`;\n } else {\n dest = `./plugins/${name}`;\n if (!fs.existsSync('./plugins')) fs.mkdirSync('./plugins');\n }\n\n if (fs.existsSync(dest)) {\n err('A directory already exists at the desired plugin location.');\n process.exit(1);\n }\n\n log('Initializing new', type.yellow, 'plugin', name.cyan, '...');\n\n const templateData: Record<string, string> = {\n name,\n author: author ?? 'AUTHOR',\n omeggaVersion: VERSION,\n };\n\n const copyAndRender = async (src: string, dest: string) => {\n const stats = fs.statSync(src);\n // remove .rename suffix from files\n dest = dest.replace(/\\.rename$/, '');\n if (stats.isDirectory()) {\n await fs.promises.mkdir(dest);\n const contents = await fs.promises.readdir(src);\n for (const child of contents)\n await copyAndRender(path.join(src, child), path.join(dest, child));\n } else {\n // copy and render the file\n const data = (await fs.promises.readFile(src)).toString();\n const mode = EXECUTABLES.includes(path.basename(dest)) ? 0o755 : 0o644;\n\n await fs.promises.writeFile(\n dest,\n data.replace(/{{(\\w+)}}/g, (_, p) => templateData[p] ?? `{{${p}}}`),\n { mode },\n );\n }\n };\n\n const src = path.join(__dirname, `../../templates/${type}`);\n\n verboseLog('Copying and rendering template...');\n await copyAndRender(src, dest);\n\n if (hasbin.sync('git')) {\n verboseLog('Running', 'git init'.yellow, 'in the new plugin directory ...');\n await exec('git init', { cwd: dest });\n }\n\n if (fs.existsSync(path.join(src, 'package.json'))) {\n verboseLog('Running', 'npm i'.yellow, 'in the new plugin directory ...');\n try {\n await exec('npm i', { cwd: dest });\n } catch (e) {\n log('Warning: npm i'.yellow, 'failed to execute. Proceeding anyway...');\n }\n }\n\n log('Initialized', type.yellow, 'plugin', `${name}`.cyan, 'successfully!');\n}\n\nfunction pluginLoaderFactory() {\n const workDir = getWorkDir();\n if (!workDir) {\n err('Not an omegga directory, run ', 'omegga init'.yellow, 'to setup one.');\n process.exit(1);\n }\n return new PluginLoader(workDir);\n}\n\n/** Loads in a plugin and it's documentation. */\nasync function loadPlugin(pluginName: string) {\n const pluginLoader = pluginLoaderFactory();\n const foundPluginDirectory = fs\n .readdirSync(pluginLoader.path)\n .find(dir => dir.toLowerCase() === pluginName.toLowerCase());\n if (!foundPluginDirectory) {\n err(\n `Plugin ${pluginName} not found! Make sure to use the plugin's directory name.`,\n );\n process.exit(1);\n }\n const plugin = await pluginLoader.scanPlugin(\n path.join(pluginLoader.path, foundPluginDirectory),\n );\n if (!plugin) {\n err(`Plugin ${pluginName} failed to load!`);\n process.exit(1);\n }\n return plugin;\n}\n\n/** Get a loaded plugin's config documentation or exit. */\nfunction getConfigDoc(plugin: Awaited<ReturnType<typeof loadPlugin>>) {\n const configDoc = plugin.getDocumentation()?.config;\n if (!configDoc) {\n err('Plugin', plugin.getName().cyan, 'has no config documentation');\n process.exit(1);\n }\n return configDoc;\n}\n\nasync function listConfig(pluginName: string, json = false) {\n const plugin = await loadPlugin(pluginName);\n // plugins without a config section are valid; list only skips unknown keys\n const configDoc = plugin.getDocumentation()?.config ?? {};\n const config = (await plugin.storage.getConfig()) ?? {};\n if (json) {\n console.log(JSON.stringify(config, null, 2));\n } else {\n for (const key in config) {\n if (!configDoc[key]) continue; // Skip unknown config keys.\n const value = config[key];\n log(\n key.cyan,\n '=',\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ? value.toString().yellow\n : JSON.stringify(value).yellow,\n );\n }\n }\n process.exit();\n}\n\nasync function getConfig(pluginName: string, configName: string, json = false) {\n const plugin = await loadPlugin(pluginName);\n const configDoc = getConfigDoc(plugin)[configName];\n if (configDoc === undefined) {\n err('Config', configName.cyan, 'not found');\n process.exit(1);\n }\n const config = (await plugin.storage.getConfig()) ?? {};\n if (json) {\n console.log(JSON.stringify(config[configName], null, 2));\n } else {\n log(config[configName]);\n }\n process.exit();\n}\n\nasync function setConfig(\n pluginName: string,\n configName: string,\n valueString: string,\n) {\n const plugin = await loadPlugin(pluginName);\n const configDoc = getConfigDoc(plugin)[configName];\n if (configDoc === undefined) {\n err('Config', configName.cyan, 'not found');\n process.exit(1);\n }\n\n // Parse the value string into a value of the correct type for the config.\n let parsed;\n switch (configDoc.type) {\n case 'boolean':\n parsed = valueString === 'true';\n break;\n case 'number':\n parsed = Number(valueString);\n if (isNaN(parsed)) {\n err('Invalid number value', valueString.yellow);\n process.exit(1);\n }\n break;\n case 'string':\n parsed = valueString;\n break;\n case 'enum':\n if (!configDoc.options.includes(valueString)) {\n err(\n 'Config',\n configName.cyan,\n 'must be one of',\n configDoc.options.join(', ').yellow,\n );\n process.exit(1);\n }\n parsed = valueString;\n break;\n default:\n err('set-context does not support config type', configDoc.type.cyan);\n process.exit(1);\n }\n\n const pluginConfig = (await plugin.storage.getConfig()) ?? {};\n pluginConfig[configName] = parsed;\n await plugin.storage.setConfig(pluginConfig);\n log(\n 'Set config',\n configName.cyan,\n 'of plugin',\n plugin.getName().cyan,\n 'to',\n parsed.toString().yellow,\n );\n process.exit();\n}\n\nasync function resetAllConfigs(pluginName: string, force: boolean) {\n const plugin = await loadPlugin(pluginName);\n if (!force) {\n const { answer } = await prompts([\n {\n type: 'confirm',\n name: 'answer',\n message: 'Are you sure you want to reset all configs?',\n initial: false,\n },\n ]);\n if (!answer) {\n log('Reset aborted.');\n process.exit(1);\n }\n }\n await plugin.storage.wipeConfig();\n await plugin.storage.init();\n log('Reset all configs of plugin', plugin.getName().cyan);\n process.exit();\n}\n\nasync function resetConfig(pluginName: string, configName: string) {\n const plugin = await loadPlugin(pluginName);\n const configDoc = getConfigDoc(plugin)[configName];\n if (configDoc === undefined) {\n err('Config', configName.cyan, 'not found');\n process.exit(1);\n }\n const pluginConfig = (await plugin.storage.getConfig()) ?? {};\n pluginConfig[configName] = plugin.storage.getDefaultConfig()[configName];\n await plugin.storage.setConfig(pluginConfig);\n log(\n 'Reset config',\n configName.cyan,\n 'of plugin',\n plugin.getName().cyan,\n 'to',\n pluginConfig[configName],\n );\n process.exit();\n}\n\nexport default {\n install,\n update,\n check,\n init,\n listConfig,\n getConfig,\n setConfig,\n resetAllConfigs,\n resetConfig,\n};\n"],"names":["promisify","execNonPromise","config.store","config.find","plugin","Logger","soft","VERSION","ResetMode","e","src","dest","PluginLoader","config"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../src/cli/plugin.ts"],"sourcesContent":["import Logger from '@/logger';\nimport soft from '@/softconfig';\nimport * as config from '@config';\nimport { PluginLoader } from '@omegga/plugin';\nimport { exec as execNonPromise } from 'node:child_process';\nimport 'colors';\nimport fs from 'node:fs';\nimport hasbin from 'hasbin';\nimport path from 'node:path';\nimport prompts from 'prompts';\nimport semver from 'semver';\nimport simpleGit, {\n ResetMode,\n type SimpleGit,\n type StatusResult,\n} from 'simple-git';\nimport { promisify } from 'node:util';\nimport { VERSION } from '@/version';\n\nconst exec = promisify(execNonPromise);\n\nconst MAIN_BRANCHES = ['master', 'main'];\n\n// get the working directory for omegga\nfunction getWorkDir() {\n // default working directory is the one specified in config\n let workDir = config.store.get('defaultOmegga');\n verboseLog('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 const confFile = config.find(workDir);\n\n return confFile\n ? path.resolve(process.cwd(), path.dirname(confFile))\n : undefined;\n}\n\ninterface IPlugin {\n name?: string;\n type: string | 'raw';\n url: string;\n}\n\ninterface IInstalledPlugin {\n name: string;\n path?: string;\n git?: SimpleGit;\n}\n\ninterface ITransformer {\n pattern: RegExp;\n fn(match: Record<string, string>): IPlugin;\n}\n\nconst PLUGIN_TYPES = ['safe', 'safe-ts', 'unsafe', 'rust', 'rpc'];\ntype PluginType = (typeof PLUGIN_TYPES)[number];\n\n// plugin url transformers\nconst transformers: ITransformer[] = [\n {\n // github transformer\n pattern: /^gh:(?<owner>[^/]+)\\/(?<repo>[^/]+)$/,\n fn: ({ owner, repo }) => ({\n type: 'short',\n name: repo,\n url: `https://github.com/${owner}/omegga-${repo}`,\n }),\n },\n {\n // gitlab transformer\n pattern: /^gl:(?<owner>[^/]+)\\/(?<repo>[^/]+)$/,\n fn: ({ owner, repo }) => ({\n type: 'short',\n name: repo,\n url: `https://gitlab.com/${owner}/omegga-${repo}`,\n }),\n },\n];\n\n// convert a shortened url into a full length one\nconst transformUrl = (url: string): IPlugin => {\n for (const t of transformers) {\n const match = url.match(t.pattern);\n if (match?.groups) return t.fn(match.groups);\n }\n return { type: 'raw', url };\n};\n\nlet needsNL = false;\n\n// rewrite a console line\nconst rewriteLine = (...args: string[]) => {\n // stdout has no cursor controls when omegga is piped or run in a container\n if (process.stdout.isTTY) {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n }\n process.stdout.write(args.join(' '));\n needsNL = true;\n};\n\n// logging helper functions\nconst plg = (plugin: IPlugin | IInstalledPlugin, ...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.log();\n }\n console.log(plugin.name, '>>'.green, ...args);\n};\nconst plgLog = (plugin: IPlugin | IInstalledPlugin, ...args: any[]) => {\n if (Logger.VERBOSE) plg(plugin, ...args);\n else\n rewriteLine(\n plugin.name ?? ('url' in plugin ? plugin.url : ''),\n '>>'.green,\n ...args,\n );\n};\nconst plgWarn = (plugin: IPlugin | IInstalledPlugin, ...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.warn();\n }\n console.warn(plugin.name, 'W>'.yellow, ...args);\n};\nconst plgErr = (plugin: IPlugin | IInstalledPlugin, ...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.error();\n }\n console.error(plugin.name, '!>'.red, ...args);\n};\n\nconst err = (...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.error();\n }\n console.error('!>'.red, ...args);\n};\nconst log = (...args: any[]) => {\n if (needsNL) {\n needsNL = false;\n console.log();\n }\n console.log('>>'.green, ...args);\n};\nconst verboseLog = (...args: any[]) => {\n if (!Logger.VERBOSE) return;\n if (needsNL) {\n needsNL = false;\n console.log();\n }\n console.log('V>'.magenta, ...args);\n};\n\nfunction checkPlugin(\n omeggaPath: string,\n plugin: (IPlugin & { name: string }) | IInstalledPlugin,\n) {\n const pluginPath = path.join(omeggaPath, soft.PLUGIN_PATH, plugin.name);\n\n // check for the plugin file, whatever it's called\n if (fs.existsSync(path.join(pluginPath, soft.PLUGIN_FILE))) {\n if (needsNL) {\n console.log();\n needsNL = false;\n }\n plgLog(plugin, 'Checking plugin file...');\n let data;\n try {\n data = JSON.parse(\n fs.readFileSync(path.join(pluginPath, soft.PLUGIN_FILE), 'utf8'),\n );\n } catch (e) {\n plgErr(plugin, 'Error reading plugin file', e);\n return false;\n }\n\n // make sure this plugin version is okay.\n // in the future, this may include deprecation warnings and format changes\n if (data.formatVersion !== 1) {\n plgWarn(\n plugin,\n 'WARNING - Plugin file has invalid',\n 'formatVersion'.yellow + '. Expected',\n '1'.yellow,\n );\n return;\n }\n\n // check the omeggaVersion field of the plugin file\n if (!data.omeggaVersion || !semver.validRange(data.omeggaVersion)) {\n plgWarn(\n plugin,\n 'WARNING - Plugin file has invalid',\n 'omeggaVersion'.yellow + '. Expected semver expression',\n );\n return false;\n } else if (!semver.satisfies(VERSION, data.omeggaVersion)) {\n plgWarn(\n plugin,\n `WARNING - Plugin is not made for this version of omegga (${VERSION.yellow} vs ${data.omeggaVersion.yellow})`,\n );\n return false;\n }\n\n plgLog(plugin, 'Plugin file', 'OK'.green);\n return true;\n }\n\n // no plugin file, no problem!\n plgWarn(\n plugin,\n `WARNING - Plugin is missing plugin file (${soft.PLUGIN_FILE}), this may be a problem in future versions`,\n );\n return true;\n}\n\n// install plugins from a list of plugins\nexport async function install(plugins: string[], _options: unknown) {\n const omeggaPath = getWorkDir();\n if (!omeggaPath)\n return err(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n\n log('Attempting to install', (plugins.length + '').yellow, 'plugins...');\n\n for (const pluginUrl of plugins) {\n const transformed = transformUrl(pluginUrl);\n\n // if the plugin wasn't transformed, try to extract its name from the git url\n let name = transformed.name;\n if (!name) {\n try {\n name = path.parse(transformed.url).name.replace(/^omegga-/, '');\n } catch (e) {\n console.error('!>'.red, 'Error parsing name from url', transformed.url);\n break;\n }\n }\n const plugin = { ...transformed, name };\n\n log(\n 'Installing plugin',\n plugin.name.yellow,\n 'from',\n plugin.url.yellow + '...',\n );\n\n // plugin absolute path\n const pluginPath = path.join(omeggaPath, soft.PLUGIN_PATH, plugin.name);\n\n // check if plugin already exists\n // TODO: if force is passed in, remove the old directory\n if (\n fs.existsSync(pluginPath) &&\n fs.existsSync(path.join(pluginPath, 'doc.json'))\n ) {\n plgErr(\n plugin,\n 'Directory already exists! Try',\n ('omegga update ' + plugin.name).yellow,\n 'or check for plugin name collisions',\n );\n continue;\n }\n\n if (!fs.existsSync(pluginPath)) {\n // create plugin local directory\n try {\n fs.mkdirSync(pluginPath, { recursive: true });\n } catch (e) {\n plgErr(plugin, 'Error creating plugin directory', e);\n }\n }\n\n // clone the plugin from git\n try {\n plgLog(plugin, 'Cloning...');\n const git = simpleGit(pluginPath);\n await git.clone(plugin.url, pluginPath);\n } catch (e) {\n plgErr(plugin, 'Error cloning plugin', e);\n }\n\n // check for the plugin file for issues\n // TODO: if force is passed in, ignore the plugin check\n if (!checkPlugin(omeggaPath, plugin)) continue;\n\n const postInstallPath = path.join(pluginPath, soft.PLUGIN_POSTINSTALL);\n if (fs.existsSync(postInstallPath)) {\n plgLog(plugin, 'Running post install script...');\n try {\n verboseLog('Changing permission of', postInstallPath);\n fs.chmodSync(postInstallPath, '0755');\n verboseLog('Executing bash file');\n const { stdout, stderr } = await exec(postInstallPath, {\n cwd: pluginPath,\n shell: 'bash',\n });\n\n if (stderr.length) plgErr(plugin, stderr);\n\n verboseLog(stdout);\n } catch (e) {\n plgErr(plugin, 'Error running post install script:', e);\n }\n }\n }\n}\nexport async function update(pluginsNames: string[], _options: unknown) {\n const omeggaPath = getWorkDir();\n if (!omeggaPath)\n return err(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n\n const pluginFolder = path.join(omeggaPath, soft.PLUGIN_PATH);\n\n // if no plugins are passed in, use every plugin in the plugins folder\n if (pluginsNames.length === 0) {\n pluginsNames = fs.readdirSync(pluginFolder);\n }\n\n const plugins: IInstalledPlugin[] = pluginsNames\n .map(dir => path.join(pluginFolder, dir))\n // every plugin must be in a directory\n .filter(\n dir =>\n fs.existsSync(dir) &&\n fs.lstatSync(dir).isDirectory() &&\n fs.existsSync(path.join(dir, '.git')),\n )\n .map(dir => ({ name: path.basename(dir) }));\n\n if (plugins.length === 0) {\n log('Found no plugins that can be updated');\n return;\n }\n\n log('Checking', (plugins.length + '').yellow, 'plugins for updates...');\n\n // list of plugins that will be updated\n const pluginsToUpdate: (IInstalledPlugin & {\n path: string;\n git: SimpleGit;\n })[] = [];\n\n for (const plugin of plugins) {\n if (needsNL) {\n console.log();\n needsNL = false;\n }\n plgLog(plugin, 'Checking...');\n const pluginPath = path.join(pluginFolder, plugin.name);\n plugin.path = pluginPath;\n const git = simpleGit(pluginPath);\n plugin.git = git;\n if (!(await git.checkIsRepo())) {\n plgErr(plugin, 'No git repo detected');\n continue;\n }\n\n let status: StatusResult;\n // get git status\n try {\n status = await git.status();\n } catch (e) {\n plgErr(plugin, 'Error getting status', e);\n continue;\n }\n\n try {\n // check for uncommitted changes\n if (status.files.some(f => f.working_dir !== '?')) {\n plgErr(plugin, 'Detected uncommitted changes - ignoring');\n continue;\n }\n\n const remotes = await git.getRemotes();\n const branches = await git.branch();\n\n // check if we're on a weird branch\n if (!MAIN_BRANCHES.includes(branches.current)) {\n plgErr(plugin, 'Not on a main branch - ignoring');\n continue;\n }\n\n // try to correct a weird detached branch\n if (\n remotes.length === 1 &&\n remotes[0].name === 'origin' &&\n !status.tracking\n ) {\n let skip = false;\n for (const branch of MAIN_BRANCHES) {\n if (\n branches.current === branch &&\n branches.branches[`remotes/origin/${branch}`]\n ) {\n plgLog(plugin, 'Correcting upstream...');\n try {\n await git.branch({ '--set-upstream-to': `origin/${branch}` });\n status = await git.status();\n break;\n } catch (e) {\n plgErr(plugin, 'Error getting status/fixing upstream branch', e);\n skip = true;\n break;\n }\n }\n }\n if (skip) continue;\n }\n\n // this should be corrected by the above check, though if it's not I am not fighting git lol\n if (!status.tracking) {\n plgErr(plugin, 'No upstream branch - ignoring');\n continue;\n }\n\n // local developers, publish your code please!!! :)\n if (remotes.length === 0) {\n plgErr(plugin, 'No remotes - ignoring');\n continue;\n }\n\n try {\n plgLog(plugin, 'Fetching...');\n await git.fetch();\n status = await git.status();\n } catch (e) {\n plgErr(plugin, 'Error fetching remote code', e);\n continue;\n }\n\n if (status.ahead > 0) {\n plgErr(plugin, 'Detected plugin is ahead - ignoring');\n continue;\n }\n\n if (status.behind === 0) {\n plgLog(plugin, 'Already up-to-date!'.green);\n continue;\n }\n\n plgLog(plugin, 'Update available');\n pluginsToUpdate.push({ ...plugin, path: pluginPath, git });\n } catch (e) {\n plgErr(plugin, 'Error', e);\n }\n }\n\n if (pluginsToUpdate.length === 0) {\n log('All plugins are currently up-to-date');\n return;\n }\n\n log('Updating', (pluginsToUpdate.length + '').yellow, 'plugins...');\n let updates = 0;\n\n for (const plugin of pluginsToUpdate) {\n const { git } = plugin;\n if (needsNL) {\n console.log();\n needsNL = false;\n }\n plgLog(plugin, 'Creating backup branch...');\n try {\n const branches = await git.branch();\n const mainBranch =\n MAIN_BRANCHES.find(b => branches.branches[b]) ?? MAIN_BRANCHES[0];\n if (branches.branches['omegga-upgrade-backup']) {\n plgLog(plugin, 'Deleting leftover backup branch...');\n await git.deleteLocalBranch('omegga-upgrade-backup', true);\n }\n await git.checkoutBranch('omegga-upgrade-backup', mainBranch);\n await git.branch({ '--set-upstream-to': `origin/${mainBranch}` });\n await git.checkout(mainBranch);\n plgLog(plugin, 'Pulling update...');\n await git.pull();\n if ((await git.status()).behind > 0) {\n throw '- still behind?';\n }\n plgLog(plugin, 'Checking plugin versions...');\n if (!checkPlugin(omeggaPath, plugin)) {\n throw 'Incompatible';\n }\n\n const postInstallPath = path.join(plugin.path, soft.PLUGIN_POSTINSTALL);\n if (fs.existsSync(postInstallPath)) {\n plgLog(plugin, 'Running post install script...');\n try {\n fs.chmodSync(postInstallPath, '0755');\n const { stdout, stderr } = await exec(postInstallPath, {\n cwd: plugin.path,\n shell: 'bash',\n });\n\n if (stderr.length) plgErr(plugin, stderr);\n\n verboseLog(stdout);\n } catch (e) {\n plgErr(plugin, 'Error running post install script:', e);\n }\n }\n\n plgLog(plugin, 'Updated!'.green);\n updates++;\n } catch (e) {\n plgErr(\n plugin,\n 'Error updating - attempting to restore from backup branch',\n e,\n );\n try {\n const branches = await git.branch();\n if (!MAIN_BRANCHES.includes(branches.current)) {\n plgErr(\n plugin,\n 'Not on expected branch - exiting before I break more things',\n );\n continue;\n }\n\n const mainBranch =\n MAIN_BRANCHES.find(b => branches.branches[b]) ?? MAIN_BRANCHES[0];\n\n plg(plugin, 'Resetting current branch');\n await git.reset(ResetMode.HARD);\n plgLog(plugin, 'Attempting to checkout backup branch');\n await git.checkout('omegga-upgrade-backup');\n plgLog(plugin, `Replacing ${mainBranch} with backup`);\n await git.deleteLocalBranch(mainBranch);\n await git.checkoutBranch(mainBranch, 'omegga-upgrade-backup');\n plgLog(plugin, 'Restored to backup branch');\n\n if ((await git.branch()).current !== mainBranch) {\n plgErr(\n plugin,\n `Failed to checkout newly created ${mainBranch} branch`,\n );\n continue;\n } else {\n plgWarn(plugin, 'Restored from backup and plugin not updated...');\n }\n } catch (e) {\n plgErr(plugin, 'Error restoring from backup... Whelp...');\n }\n continue;\n }\n }\n\n log('Updated', (updates + '').yellow, 'plugins!');\n}\n\nexport async function check(pluginNames: string[], _options: unknown) {\n const omeggaPath = getWorkDir();\n if (!omeggaPath)\n return err(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n\n const pluginFolder = path.join(omeggaPath, soft.PLUGIN_PATH);\n\n // if no plugins are passed in, use every plugin in the plugins folder\n if (pluginNames.length === 0) {\n pluginNames = fs.readdirSync(pluginFolder);\n }\n\n const plugins: IInstalledPlugin[] = pluginNames\n .map(dir => path.join(pluginFolder, dir))\n // every plugin must be in a directory\n .filter(\n dir =>\n fs.existsSync(dir) &&\n fs.lstatSync(dir).isDirectory() &&\n fs.existsSync(path.join(dir, '.git')),\n )\n .map(dir => ({ name: path.basename(dir) }));\n\n if (plugins.length === 0) {\n log('Found no plugins that can be checked');\n return;\n }\n\n log(\n 'Checking',\n (plugins.length + '').yellow,\n 'plugins for valid plugin files',\n );\n\n for (const plugin of plugins) {\n const pluginPath = path.join(pluginFolder, plugin.name);\n plugin.path = pluginPath;\n const git = simpleGit(pluginPath);\n plugin.git = git;\n if (!(await git.checkIsRepo())) {\n plgErr(plugin, 'No git repo detected');\n continue;\n }\n checkPlugin(omeggaPath, plugin);\n }\n console.log();\n}\n\nconst EXECUTABLES = ['setup.sh', 'omegga_plugin'];\n\nasync function init() {\n const { author, ...response } = await prompts([\n {\n type: 'text',\n name: 'name',\n message: 'What would you like to ' + 'name'.yellow + ' your plugin?',\n validate: value =>\n value.match(/^[\\w-_]+$/) ? true : 'Invalid plugin name!',\n },\n {\n type: 'select',\n name: 'type',\n message:\n 'What ' + 'type'.yellow + ' of plugin would you like to initialize?',\n choices: [\n { title: 'safe ' + '(default)'.italic, value: 'safe' },\n { title: 'unsafe', value: 'unsafe' },\n { title: 'rust', value: 'rust' },\n { title: 'rpc', value: 'rpc' },\n ],\n },\n {\n type: prev => (prev == 'safe' ? 'confirm' : null),\n name: 'ts',\n message:\n 'Would you like to use ' + 'TypeScript'.yellow + ' in your plugin?',\n initial: false,\n },\n {\n type: 'text',\n name: 'author',\n message: 'Who is the ' + 'author'.yellow + ' of this plugin?',\n },\n ]);\n\n const name = response.name;\n const type: PluginType =\n response.type == 'safe' && response.ts ? 'safe-ts' : response.type;\n\n if (!PLUGIN_TYPES.includes(type)) {\n err('Invalid plugin type', type.red, '!');\n process.exit(1);\n }\n\n let dest: string;\n if (!config.find('.')) {\n log(\n 'Warning:'.yellow,\n 'This is not an omegga installation, initializing here instead...',\n );\n dest = `./${name}`;\n } else {\n dest = `./plugins/${name}`;\n if (!fs.existsSync('./plugins')) fs.mkdirSync('./plugins');\n }\n\n if (fs.existsSync(dest)) {\n err('A directory already exists at the desired plugin location.');\n process.exit(1);\n }\n\n log('Initializing new', type.yellow, 'plugin', name.cyan, '...');\n\n const templateData: Record<string, string> = {\n name,\n author: author ?? 'AUTHOR',\n omeggaVersion: VERSION,\n };\n\n const copyAndRender = async (src: string, dest: string) => {\n const stats = fs.statSync(src);\n // remove .rename suffix from files\n dest = dest.replace(/\\.rename$/, '');\n if (stats.isDirectory()) {\n await fs.promises.mkdir(dest);\n const contents = await fs.promises.readdir(src);\n for (const child of contents)\n await copyAndRender(path.join(src, child), path.join(dest, child));\n } else {\n // copy and render the file\n const data = (await fs.promises.readFile(src)).toString();\n const mode = EXECUTABLES.includes(path.basename(dest)) ? 0o755 : 0o644;\n\n await fs.promises.writeFile(\n dest,\n data.replace(/{{(\\w+)}}/g, (_, p) => templateData[p] ?? `{{${p}}}`),\n { mode },\n );\n }\n };\n\n const src = path.join(__dirname, `../../templates/${type}`);\n\n verboseLog('Copying and rendering template...');\n await copyAndRender(src, dest);\n\n if (hasbin.sync('git')) {\n verboseLog('Running', 'git init'.yellow, 'in the new plugin directory ...');\n await exec('git init', { cwd: dest });\n }\n\n if (fs.existsSync(path.join(src, 'package.json'))) {\n verboseLog('Running', 'npm i'.yellow, 'in the new plugin directory ...');\n try {\n await exec('npm i', { cwd: dest });\n } catch (e) {\n log('Warning: npm i'.yellow, 'failed to execute. Proceeding anyway...');\n }\n }\n\n log('Initialized', type.yellow, 'plugin', `${name}`.cyan, 'successfully!');\n}\n\nfunction pluginLoaderFactory() {\n const workDir = getWorkDir();\n if (!workDir) {\n err('Not an omegga directory, run ', 'omegga init'.yellow, 'to setup one.');\n process.exit(1);\n }\n return new PluginLoader(workDir);\n}\n\n/** Loads in a plugin and it's documentation. */\nasync function loadPlugin(pluginName: string) {\n const pluginLoader = pluginLoaderFactory();\n const foundPluginDirectory = fs\n .readdirSync(pluginLoader.path)\n .find(dir => dir.toLowerCase() === pluginName.toLowerCase());\n if (!foundPluginDirectory) {\n err(\n `Plugin ${pluginName} not found! Make sure to use the plugin's directory name.`,\n );\n process.exit(1);\n }\n const plugin = await pluginLoader.scanPlugin(\n path.join(pluginLoader.path, foundPluginDirectory),\n );\n if (!plugin) {\n err(`Plugin ${pluginName} failed to load!`);\n process.exit(1);\n }\n return plugin;\n}\n\n/** Get a loaded plugin's config documentation or exit. */\nfunction getConfigDoc(plugin: Awaited<ReturnType<typeof loadPlugin>>) {\n const configDoc = plugin.getDocumentation()?.config;\n if (!configDoc) {\n err('Plugin', plugin.getName().cyan, 'has no config documentation');\n process.exit(1);\n }\n return configDoc;\n}\n\nasync function listConfig(pluginName: string, json = false) {\n const plugin = await loadPlugin(pluginName);\n // plugins without a config section are valid; list only skips unknown keys\n const configDoc = plugin.getDocumentation()?.config ?? {};\n const config = (await plugin.storage.getConfig()) ?? {};\n if (json) {\n console.log(JSON.stringify(config, null, 2));\n } else {\n for (const key in config) {\n if (!configDoc[key]) continue; // Skip unknown config keys.\n const value = config[key];\n log(\n key.cyan,\n '=',\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ? value.toString().yellow\n : JSON.stringify(value).yellow,\n );\n }\n }\n process.exit();\n}\n\nasync function getConfig(pluginName: string, configName: string, json = false) {\n const plugin = await loadPlugin(pluginName);\n const configDoc = getConfigDoc(plugin)[configName];\n if (configDoc === undefined) {\n err('Config', configName.cyan, 'not found');\n process.exit(1);\n }\n const config = (await plugin.storage.getConfig()) ?? {};\n if (json) {\n console.log(JSON.stringify(config[configName], null, 2));\n } else {\n log(config[configName]);\n }\n process.exit();\n}\n\nasync function setConfig(\n pluginName: string,\n configName: string,\n valueString: string,\n) {\n const plugin = await loadPlugin(pluginName);\n const configDoc = getConfigDoc(plugin)[configName];\n if (configDoc === undefined) {\n err('Config', configName.cyan, 'not found');\n process.exit(1);\n }\n\n // Parse the value string into a value of the correct type for the config.\n let parsed;\n switch (configDoc.type) {\n case 'boolean':\n parsed = valueString === 'true';\n break;\n case 'number':\n parsed = Number(valueString);\n if (isNaN(parsed)) {\n err('Invalid number value', valueString.yellow);\n process.exit(1);\n }\n break;\n case 'string':\n parsed = valueString;\n break;\n case 'enum':\n if (!configDoc.options.includes(valueString)) {\n err(\n 'Config',\n configName.cyan,\n 'must be one of',\n configDoc.options.join(', ').yellow,\n );\n process.exit(1);\n }\n parsed = valueString;\n break;\n default:\n err('set-context does not support config type', configDoc.type.cyan);\n process.exit(1);\n }\n\n const pluginConfig = (await plugin.storage.getConfig()) ?? {};\n pluginConfig[configName] = parsed;\n await plugin.storage.setConfig(pluginConfig);\n log(\n 'Set config',\n configName.cyan,\n 'of plugin',\n plugin.getName().cyan,\n 'to',\n parsed.toString().yellow,\n );\n process.exit();\n}\n\nasync function resetAllConfigs(pluginName: string, force: boolean) {\n const plugin = await loadPlugin(pluginName);\n if (!force) {\n const { answer } = await prompts([\n {\n type: 'confirm',\n name: 'answer',\n message: 'Are you sure you want to reset all configs?',\n initial: false,\n },\n ]);\n if (!answer) {\n log('Reset aborted.');\n process.exit(1);\n }\n }\n await plugin.storage.wipeConfig();\n await plugin.storage.init();\n log('Reset all configs of plugin', plugin.getName().cyan);\n process.exit();\n}\n\nasync function resetConfig(pluginName: string, configName: string) {\n const plugin = await loadPlugin(pluginName);\n const configDoc = getConfigDoc(plugin)[configName];\n if (configDoc === undefined) {\n err('Config', configName.cyan, 'not found');\n process.exit(1);\n }\n const pluginConfig = (await plugin.storage.getConfig()) ?? {};\n pluginConfig[configName] = plugin.storage.getDefaultConfig()[configName];\n await plugin.storage.setConfig(pluginConfig);\n log(\n 'Reset config',\n configName.cyan,\n 'of plugin',\n plugin.getName().cyan,\n 'to',\n pluginConfig[configName],\n );\n process.exit();\n}\n\nexport default {\n install,\n update,\n check,\n init,\n listConfig,\n getConfig,\n setConfig,\n resetAllConfigs,\n resetConfig,\n};\n"],"names":["promisify","execNonPromise","config.store","config.find","plugin","Logger","soft","VERSION","ResetMode","e","src","dest","PluginLoader","config"],"mappings":";;;;;;;;;;;;;;;;AAmBA,MAAM,OAAOA,UAAAA,UAAUC,uBAAc;AAErC,MAAM,gBAAgB,CAAC,UAAU,MAAM;AAGvC,SAAS,aAAa;AAEpB,MAAI,UAAUC,MAAAA,MAAa,IAAI,eAAe;AAC9C,aAAW,2BAA2B,QAAQ,MAAM;AAGpD,MAAIC,WAAY,GAAG,EAAG,WAAU;AAEhC,QAAM,WAAWA,MAAAA,KAAY,OAAO;AAEpC,SAAO,WACH,KAAK,QAAQ,QAAQ,OAAO,KAAK,QAAQ,QAAQ,CAAC,IAClD;AACN;AAmBA,MAAM,eAAe,CAAC,QAAQ,WAAW,UAAU,QAAQ,KAAK;AAIhE,MAAM,eAA+B;AAAA,EACnC;AAAA;AAAA,IAEE,SAAS;AAAA,IACT,IAAI,CAAC,EAAE,OAAO,YAAY;AAAA,MACxB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK,sBAAsB,KAAK,WAAW,IAAI;AAAA,IAAA;AAAA,EACjD;AAAA,EAEF;AAAA;AAAA,IAEE,SAAS;AAAA,IACT,IAAI,CAAC,EAAE,OAAO,YAAY;AAAA,MACxB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK,sBAAsB,KAAK,WAAW,IAAI;AAAA,IAAA;AAAA,EACjD;AAEJ;AAGA,MAAM,eAAe,CAAC,QAAyB;AAC7C,aAAW,KAAK,cAAc;AAC5B,UAAM,QAAQ,IAAI,MAAM,EAAE,OAAO;AACjC,QAAI,OAAO,OAAQ,QAAO,EAAE,GAAG,MAAM,MAAM;AAAA,EAC7C;AACA,SAAO,EAAE,MAAM,OAAO,IAAA;AACxB;AAEA,IAAI,UAAU;AAGd,MAAM,cAAc,IAAI,SAAmB;AAEzC,MAAI,QAAQ,OAAO,OAAO;AACxB,YAAQ,OAAO,UAAU,CAAC;AAC1B,YAAQ,OAAO,SAAS,CAAC;AAAA,EAC3B;AACA,UAAQ,OAAO,MAAM,KAAK,KAAK,GAAG,CAAC;AACnC,YAAU;AACZ;AAGA,MAAM,MAAM,CAACC,YAAuC,SAAgB;AAClE,MAAI,SAAS;AACX,cAAU;AACV,YAAQ,IAAA;AAAA,EACV;AACA,UAAQ,IAAIA,QAAO,MAAM,KAAK,OAAO,GAAG,IAAI;AAC9C;AACA,MAAM,SAAS,CAACA,YAAuC,SAAgB;AACrE,MAAIC,OAAAA,QAAO,QAAS,KAAID,SAAQ,GAAG,IAAI;AAAA;AAErC;AAAA,MACEA,QAAO,SAAS,SAASA,UAASA,QAAO,MAAM;AAAA,MAC/C,KAAK;AAAA,MACL,GAAG;AAAA,IAAA;AAET;AACA,MAAM,UAAU,CAACA,YAAuC,SAAgB;AACtE,MAAI,SAAS;AACX,cAAU;AACV,YAAQ,KAAA;AAAA,EACV;AACA,UAAQ,KAAKA,QAAO,MAAM,KAAK,QAAQ,GAAG,IAAI;AAChD;AACA,MAAM,SAAS,CAACA,YAAuC,SAAgB;AACrE,MAAI,SAAS;AACX,cAAU;AACV,YAAQ,MAAA;AAAA,EACV;AACA,UAAQ,MAAMA,QAAO,MAAM,KAAK,KAAK,GAAG,IAAI;AAC9C;AAEA,MAAM,MAAM,IAAI,SAAgB;AAC9B,MAAI,SAAS;AACX,cAAU;AACV,YAAQ,MAAA;AAAA,EACV;AACA,UAAQ,MAAM,KAAK,KAAK,GAAG,IAAI;AACjC;AACA,MAAM,MAAM,IAAI,SAAgB;AAC9B,MAAI,SAAS;AACX,cAAU;AACV,YAAQ,IAAA;AAAA,EACV;AACA,UAAQ,IAAI,KAAK,OAAO,GAAG,IAAI;AACjC;AACA,MAAM,aAAa,IAAI,SAAgB;AACrC,MAAI,CAACC,OAAAA,QAAO,QAAS;AACrB,MAAI,SAAS;AACX,cAAU;AACV,YAAQ,IAAA;AAAA,EACV;AACA,UAAQ,IAAI,KAAK,SAAS,GAAG,IAAI;AACnC;AAEA,SAAS,YACP,YACAD,SACA;AACA,QAAM,aAAa,KAAK,KAAK,YAAYE,WAAAA,QAAK,aAAaF,QAAO,IAAI;AAGtE,MAAI,GAAG,WAAW,KAAK,KAAK,YAAYE,WAAAA,QAAK,WAAW,CAAC,GAAG;AAC1D,QAAI,SAAS;AACX,cAAQ,IAAA;AACR,gBAAU;AAAA,IACZ;AACA,WAAOF,SAAQ,yBAAyB;AACxC,QAAI;AACJ,QAAI;AACF,aAAO,KAAK;AAAA,QACV,GAAG,aAAa,KAAK,KAAK,YAAYE,WAAAA,QAAK,WAAW,GAAG,MAAM;AAAA,MAAA;AAAA,IAEnE,SAAS,GAAG;AACV,aAAOF,SAAQ,6BAA6B,CAAC;AAC7C,aAAO;AAAA,IACT;AAIA,QAAI,KAAK,kBAAkB,GAAG;AAC5B;AAAA,QACEA;AAAA,QACA;AAAA,QACA,gBAAgB,SAAS;AAAA,QACzB,IAAI;AAAA,MAAA;AAEN;AAAA,IACF;AAGA,QAAI,CAAC,KAAK,iBAAiB,CAAC,OAAO,WAAW,KAAK,aAAa,GAAG;AACjE;AAAA,QACEA;AAAA,QACA;AAAA,QACA,gBAAgB,SAAS;AAAA,MAAA;AAE3B,aAAO;AAAA,IACT,WAAW,CAAC,OAAO,UAAUG,QAAAA,SAAS,KAAK,aAAa,GAAG;AACzD;AAAA,QACEH;AAAA,QACA,4DAA4DG,QAAAA,QAAQ,MAAM,OAAO,KAAK,cAAc,MAAM;AAAA,MAAA;AAE5G,aAAO;AAAA,IACT;AAEA,WAAOH,SAAQ,eAAe,KAAK,KAAK;AACxC,WAAO;AAAA,EACT;AAGA;AAAA,IACEA;AAAA,IACA,4CAA4CE,mBAAK,WAAW;AAAA,EAAA;AAE9D,SAAO;AACT;AAGA,eAAsB,QAAQ,SAAmB,UAAmB;AAClE,QAAM,aAAa,WAAA;AACnB,MAAI,CAAC;AACH,WAAO;AAAA,MACL;AAAA,MACA,cAAc;AAAA,MACd;AAAA,IAAA;AAGJ,MAAI,0BAA0B,QAAQ,SAAS,IAAI,QAAQ,YAAY;AAEvE,aAAW,aAAa,SAAS;AAC/B,UAAM,cAAc,aAAa,SAAS;AAG1C,QAAI,OAAO,YAAY;AACvB,QAAI,CAAC,MAAM;AACT,UAAI;AACF,eAAO,KAAK,MAAM,YAAY,GAAG,EAAE,KAAK,QAAQ,YAAY,EAAE;AAAA,MAChE,SAAS,GAAG;AACV,gBAAQ,MAAM,KAAK,KAAK,+BAA+B,YAAY,GAAG;AACtE;AAAA,MACF;AAAA,IACF;AACA,UAAMF,UAAS,EAAE,GAAG,aAAa,KAAA;AAEjC;AAAA,MACE;AAAA,MACAA,QAAO,KAAK;AAAA,MACZ;AAAA,MACAA,QAAO,IAAI,SAAS;AAAA,IAAA;AAItB,UAAM,aAAa,KAAK,KAAK,YAAYE,WAAAA,QAAK,aAAaF,QAAO,IAAI;AAItE,QACE,GAAG,WAAW,UAAU,KACxB,GAAG,WAAW,KAAK,KAAK,YAAY,UAAU,CAAC,GAC/C;AACA;AAAA,QACEA;AAAA,QACA;AAAA,SACC,mBAAmBA,QAAO,MAAM;AAAA,QACjC;AAAA,MAAA;AAEF;AAAA,IACF;AAEA,QAAI,CAAC,GAAG,WAAW,UAAU,GAAG;AAE9B,UAAI;AACF,WAAG,UAAU,YAAY,EAAE,WAAW,MAAM;AAAA,MAC9C,SAAS,GAAG;AACV,eAAOA,SAAQ,mCAAmC,CAAC;AAAA,MACrD;AAAA,IACF;AAGA,QAAI;AACF,aAAOA,SAAQ,YAAY;AAC3B,YAAM,MAAM,UAAU,UAAU;AAChC,YAAM,IAAI,MAAMA,QAAO,KAAK,UAAU;AAAA,IACxC,SAAS,GAAG;AACV,aAAOA,SAAQ,wBAAwB,CAAC;AAAA,IAC1C;AAIA,QAAI,CAAC,YAAY,YAAYA,OAAM,EAAG;AAEtC,UAAM,kBAAkB,KAAK,KAAK,YAAYE,WAAAA,QAAK,kBAAkB;AACrE,QAAI,GAAG,WAAW,eAAe,GAAG;AAClC,aAAOF,SAAQ,gCAAgC;AAC/C,UAAI;AACF,mBAAW,0BAA0B,eAAe;AACpD,WAAG,UAAU,iBAAiB,MAAM;AACpC,mBAAW,qBAAqB;AAChC,cAAM,EAAE,QAAQ,OAAA,IAAW,MAAM,KAAK,iBAAiB;AAAA,UACrD,KAAK;AAAA,UACL,OAAO;AAAA,QAAA,CACR;AAED,YAAI,OAAO,OAAQ,QAAOA,SAAQ,MAAM;AAExC,mBAAW,MAAM;AAAA,MACnB,SAAS,GAAG;AACV,eAAOA,SAAQ,sCAAsC,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AACA,eAAsB,OAAO,cAAwB,UAAmB;AACtE,QAAM,aAAa,WAAA;AACnB,MAAI,CAAC;AACH,WAAO;AAAA,MACL;AAAA,MACA,cAAc;AAAA,MACd;AAAA,IAAA;AAGJ,QAAM,eAAe,KAAK,KAAK,YAAYE,WAAAA,QAAK,WAAW;AAG3D,MAAI,aAAa,WAAW,GAAG;AAC7B,mBAAe,GAAG,YAAY,YAAY;AAAA,EAC5C;AAEA,QAAM,UAA8B,aACjC,IAAI,CAAA,QAAO,KAAK,KAAK,cAAc,GAAG,CAAC,EAEvC;AAAA,IACC,SACE,GAAG,WAAW,GAAG,KACjB,GAAG,UAAU,GAAG,EAAE,YAAA,KAClB,GAAG,WAAW,KAAK,KAAK,KAAK,MAAM,CAAC;AAAA,EAAA,EAEvC,IAAI,CAAA,SAAQ,EAAE,MAAM,KAAK,SAAS,GAAG,EAAA,EAAI;AAE5C,MAAI,QAAQ,WAAW,GAAG;AACxB,QAAI,sCAAsC;AAC1C;AAAA,EACF;AAEA,MAAI,aAAa,QAAQ,SAAS,IAAI,QAAQ,wBAAwB;AAGtE,QAAM,kBAGC,CAAA;AAEP,aAAWF,WAAU,SAAS;AAC5B,QAAI,SAAS;AACX,cAAQ,IAAA;AACR,gBAAU;AAAA,IACZ;AACA,WAAOA,SAAQ,aAAa;AAC5B,UAAM,aAAa,KAAK,KAAK,cAAcA,QAAO,IAAI;AACtD,IAAAA,QAAO,OAAO;AACd,UAAM,MAAM,UAAU,UAAU;AAChC,IAAAA,QAAO,MAAM;AACb,QAAI,CAAE,MAAM,IAAI,eAAgB;AAC9B,aAAOA,SAAQ,sBAAsB;AACrC;AAAA,IACF;AAEA,QAAI;AAEJ,QAAI;AACF,eAAS,MAAM,IAAI,OAAA;AAAA,IACrB,SAAS,GAAG;AACV,aAAOA,SAAQ,wBAAwB,CAAC;AACxC;AAAA,IACF;AAEA,QAAI;AAEF,UAAI,OAAO,MAAM,KAAK,OAAK,EAAE,gBAAgB,GAAG,GAAG;AACjD,eAAOA,SAAQ,yCAAyC;AACxD;AAAA,MACF;AAEA,YAAM,UAAU,MAAM,IAAI,WAAA;AAC1B,YAAM,WAAW,MAAM,IAAI,OAAA;AAG3B,UAAI,CAAC,cAAc,SAAS,SAAS,OAAO,GAAG;AAC7C,eAAOA,SAAQ,iCAAiC;AAChD;AAAA,MACF;AAGA,UACE,QAAQ,WAAW,KACnB,QAAQ,CAAC,EAAE,SAAS,YACpB,CAAC,OAAO,UACR;AACA,YAAI,OAAO;AACX,mBAAW,UAAU,eAAe;AAClC,cACE,SAAS,YAAY,UACrB,SAAS,SAAS,kBAAkB,MAAM,EAAE,GAC5C;AACA,mBAAOA,SAAQ,wBAAwB;AACvC,gBAAI;AACF,oBAAM,IAAI,OAAO,EAAE,qBAAqB,UAAU,MAAM,IAAI;AAC5D,uBAAS,MAAM,IAAI,OAAA;AACnB;AAAA,YACF,SAAS,GAAG;AACV,qBAAOA,SAAQ,+CAA+C,CAAC;AAC/D,qBAAO;AACP;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,YAAI,KAAM;AAAA,MACZ;AAGA,UAAI,CAAC,OAAO,UAAU;AACpB,eAAOA,SAAQ,+BAA+B;AAC9C;AAAA,MACF;AAGA,UAAI,QAAQ,WAAW,GAAG;AACxB,eAAOA,SAAQ,uBAAuB;AACtC;AAAA,MACF;AAEA,UAAI;AACF,eAAOA,SAAQ,aAAa;AAC5B,cAAM,IAAI,MAAA;AACV,iBAAS,MAAM,IAAI,OAAA;AAAA,MACrB,SAAS,GAAG;AACV,eAAOA,SAAQ,8BAA8B,CAAC;AAC9C;AAAA,MACF;AAEA,UAAI,OAAO,QAAQ,GAAG;AACpB,eAAOA,SAAQ,qCAAqC;AACpD;AAAA,MACF;AAEA,UAAI,OAAO,WAAW,GAAG;AACvB,eAAOA,SAAQ,sBAAsB,KAAK;AAC1C;AAAA,MACF;AAEA,aAAOA,SAAQ,kBAAkB;AACjC,sBAAgB,KAAK,EAAE,GAAGA,SAAQ,MAAM,YAAY,KAAK;AAAA,IAC3D,SAAS,GAAG;AACV,aAAOA,SAAQ,SAAS,CAAC;AAAA,IAC3B;AAAA,EACF;AAEA,MAAI,gBAAgB,WAAW,GAAG;AAChC,QAAI,sCAAsC;AAC1C;AAAA,EACF;AAEA,MAAI,aAAa,gBAAgB,SAAS,IAAI,QAAQ,YAAY;AAClE,MAAI,UAAU;AAEd,aAAWA,WAAU,iBAAiB;AACpC,UAAM,EAAE,QAAQA;AAChB,QAAI,SAAS;AACX,cAAQ,IAAA;AACR,gBAAU;AAAA,IACZ;AACA,WAAOA,SAAQ,2BAA2B;AAC1C,QAAI;AACF,YAAM,WAAW,MAAM,IAAI,OAAA;AAC3B,YAAM,aACJ,cAAc,KAAK,CAAA,MAAK,SAAS,SAAS,CAAC,CAAC,KAAK,cAAc,CAAC;AAClE,UAAI,SAAS,SAAS,uBAAuB,GAAG;AAC9C,eAAOA,SAAQ,oCAAoC;AACnD,cAAM,IAAI,kBAAkB,yBAAyB,IAAI;AAAA,MAC3D;AACA,YAAM,IAAI,eAAe,yBAAyB,UAAU;AAC5D,YAAM,IAAI,OAAO,EAAE,qBAAqB,UAAU,UAAU,IAAI;AAChE,YAAM,IAAI,SAAS,UAAU;AAC7B,aAAOA,SAAQ,mBAAmB;AAClC,YAAM,IAAI,KAAA;AACV,WAAK,MAAM,IAAI,OAAA,GAAU,SAAS,GAAG;AACnC,cAAM;AAAA,MACR;AACA,aAAOA,SAAQ,6BAA6B;AAC5C,UAAI,CAAC,YAAY,YAAYA,OAAM,GAAG;AACpC,cAAM;AAAA,MACR;AAEA,YAAM,kBAAkB,KAAK,KAAKA,QAAO,MAAME,WAAAA,QAAK,kBAAkB;AACtE,UAAI,GAAG,WAAW,eAAe,GAAG;AAClC,eAAOF,SAAQ,gCAAgC;AAC/C,YAAI;AACF,aAAG,UAAU,iBAAiB,MAAM;AACpC,gBAAM,EAAE,QAAQ,OAAA,IAAW,MAAM,KAAK,iBAAiB;AAAA,YACrD,KAAKA,QAAO;AAAA,YACZ,OAAO;AAAA,UAAA,CACR;AAED,cAAI,OAAO,OAAQ,QAAOA,SAAQ,MAAM;AAExC,qBAAW,MAAM;AAAA,QACnB,SAAS,GAAG;AACV,iBAAOA,SAAQ,sCAAsC,CAAC;AAAA,QACxD;AAAA,MACF;AAEA,aAAOA,SAAQ,WAAW,KAAK;AAC/B;AAAA,IACF,SAAS,GAAG;AACV;AAAA,QACEA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAEF,UAAI;AACF,cAAM,WAAW,MAAM,IAAI,OAAA;AAC3B,YAAI,CAAC,cAAc,SAAS,SAAS,OAAO,GAAG;AAC7C;AAAA,YACEA;AAAA,YACA;AAAA,UAAA;AAEF;AAAA,QACF;AAEA,cAAM,aACJ,cAAc,KAAK,CAAA,MAAK,SAAS,SAAS,CAAC,CAAC,KAAK,cAAc,CAAC;AAElE,YAAIA,SAAQ,0BAA0B;AACtC,cAAM,IAAI,MAAMI,UAAAA,UAAU,IAAI;AAC9B,eAAOJ,SAAQ,sCAAsC;AACrD,cAAM,IAAI,SAAS,uBAAuB;AAC1C,eAAOA,SAAQ,aAAa,UAAU,cAAc;AACpD,cAAM,IAAI,kBAAkB,UAAU;AACtC,cAAM,IAAI,eAAe,YAAY,uBAAuB;AAC5D,eAAOA,SAAQ,2BAA2B;AAE1C,aAAK,MAAM,IAAI,OAAA,GAAU,YAAY,YAAY;AAC/C;AAAA,YACEA;AAAA,YACA,oCAAoC,UAAU;AAAA,UAAA;AAEhD;AAAA,QACF,OAAO;AACL,kBAAQA,SAAQ,gDAAgD;AAAA,QAClE;AAAA,MACF,SAASK,IAAG;AACV,eAAOL,SAAQ,yCAAyC;AAAA,MAC1D;AACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,YAAY,UAAU,IAAI,QAAQ,UAAU;AAClD;AAEA,eAAsB,MAAM,aAAuB,UAAmB;AACpE,QAAM,aAAa,WAAA;AACnB,MAAI,CAAC;AACH,WAAO;AAAA,MACL;AAAA,MACA,cAAc;AAAA,MACd;AAAA,IAAA;AAGJ,QAAM,eAAe,KAAK,KAAK,YAAYE,WAAAA,QAAK,WAAW;AAG3D,MAAI,YAAY,WAAW,GAAG;AAC5B,kBAAc,GAAG,YAAY,YAAY;AAAA,EAC3C;AAEA,QAAM,UAA8B,YACjC,IAAI,CAAA,QAAO,KAAK,KAAK,cAAc,GAAG,CAAC,EAEvC;AAAA,IACC,SACE,GAAG,WAAW,GAAG,KACjB,GAAG,UAAU,GAAG,EAAE,YAAA,KAClB,GAAG,WAAW,KAAK,KAAK,KAAK,MAAM,CAAC;AAAA,EAAA,EAEvC,IAAI,CAAA,SAAQ,EAAE,MAAM,KAAK,SAAS,GAAG,EAAA,EAAI;AAE5C,MAAI,QAAQ,WAAW,GAAG;AACxB,QAAI,sCAAsC;AAC1C;AAAA,EACF;AAEA;AAAA,IACE;AAAA,KACC,QAAQ,SAAS,IAAI;AAAA,IACtB;AAAA,EAAA;AAGF,aAAWF,WAAU,SAAS;AAC5B,UAAM,aAAa,KAAK,KAAK,cAAcA,QAAO,IAAI;AACtD,IAAAA,QAAO,OAAO;AACd,UAAM,MAAM,UAAU,UAAU;AAChC,IAAAA,QAAO,MAAM;AACb,QAAI,CAAE,MAAM,IAAI,eAAgB;AAC9B,aAAOA,SAAQ,sBAAsB;AACrC;AAAA,IACF;AACA,gBAAY,YAAYA,OAAM;AAAA,EAChC;AACA,UAAQ,IAAA;AACV;AAEA,MAAM,cAAc,CAAC,YAAY,eAAe;AAEhD,eAAe,OAAO;AACpB,QAAM,EAAE,QAAQ,GAAG,SAAA,IAAa,MAAM,QAAQ;AAAA,IAC5C;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,4BAA4B,OAAO,SAAS;AAAA,MACrD,UAAU,CAAA,UACR,MAAM,MAAM,WAAW,IAAI,OAAO;AAAA,IAAA;AAAA,IAEtC;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SACE,UAAU,OAAO,SAAS;AAAA,MAC5B,SAAS;AAAA,QACP,EAAE,OAAO,UAAU,YAAY,QAAQ,OAAO,OAAA;AAAA,QAC9C,EAAE,OAAO,UAAU,OAAO,SAAA;AAAA,QAC1B,EAAE,OAAO,QAAQ,OAAO,OAAA;AAAA,QACxB,EAAE,OAAO,OAAO,OAAO,MAAA;AAAA,MAAM;AAAA,IAC/B;AAAA,IAEF;AAAA,MACE,MAAM,CAAA,SAAS,QAAQ,SAAS,YAAY;AAAA,MAC5C,MAAM;AAAA,MACN,SACE,2BAA2B,aAAa,SAAS;AAAA,MACnD,SAAS;AAAA,IAAA;AAAA,IAEX;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,gBAAgB,SAAS,SAAS;AAAA,IAAA;AAAA,EAC7C,CACD;AAED,QAAM,OAAO,SAAS;AACtB,QAAM,OACJ,SAAS,QAAQ,UAAU,SAAS,KAAK,YAAY,SAAS;AAEhE,MAAI,CAAC,aAAa,SAAS,IAAI,GAAG;AAChC,QAAI,uBAAuB,KAAK,KAAK,GAAG;AACxC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI;AACJ,MAAI,CAACD,MAAAA,KAAY,GAAG,GAAG;AACrB;AAAA,MACE,WAAW;AAAA,MACX;AAAA,IAAA;AAEF,WAAO,KAAK,IAAI;AAAA,EAClB,OAAO;AACL,WAAO,aAAa,IAAI;AACxB,QAAI,CAAC,GAAG,WAAW,WAAW,EAAG,IAAG,UAAU,WAAW;AAAA,EAC3D;AAEA,MAAI,GAAG,WAAW,IAAI,GAAG;AACvB,QAAI,4DAA4D;AAChE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,oBAAoB,KAAK,QAAQ,UAAU,KAAK,MAAM,KAAK;AAE/D,QAAM,eAAuC;AAAA,IAC3C;AAAA,IACA,QAAQ,UAAU;AAAA,IAClB,eAAeI,QAAAA;AAAAA,EAAA;AAGjB,QAAM,gBAAgB,OAAOG,MAAaC,UAAiB;AACzD,UAAM,QAAQ,GAAG,SAASD,IAAG;AAE7BC,YAAOA,MAAK,QAAQ,aAAa,EAAE;AACnC,QAAI,MAAM,eAAe;AACvB,YAAM,GAAG,SAAS,MAAMA,KAAI;AAC5B,YAAM,WAAW,MAAM,GAAG,SAAS,QAAQD,IAAG;AAC9C,iBAAW,SAAS;AAClB,cAAM,cAAc,KAAK,KAAKA,MAAK,KAAK,GAAG,KAAK,KAAKC,OAAM,KAAK,CAAC;AAAA,IACrE,OAAO;AAEL,YAAM,QAAQ,MAAM,GAAG,SAAS,SAASD,IAAG,GAAG,SAAA;AAC/C,YAAM,OAAO,YAAY,SAAS,KAAK,SAASC,KAAI,CAAC,IAAI,MAAQ;AAEjE,YAAM,GAAG,SAAS;AAAA,QAChBA;AAAAA,QACA,KAAK,QAAQ,cAAc,CAAC,GAAG,MAAM,aAAa,CAAC,KAAK,KAAK,CAAC,IAAI;AAAA,QAClE,EAAE,KAAA;AAAA,MAAK;AAAA,IAEX;AAAA,EACF;AAEA,QAAM,MAAM,KAAK,KAAK,WAAW,mBAAmB,IAAI,EAAE;AAE1D,aAAW,mCAAmC;AAC9C,QAAM,cAAc,KAAK,IAAI;AAE7B,MAAI,OAAO,KAAK,KAAK,GAAG;AACtB,eAAW,WAAW,WAAW,QAAQ,iCAAiC;AAC1E,UAAM,KAAK,YAAY,EAAE,KAAK,MAAM;AAAA,EACtC;AAEA,MAAI,GAAG,WAAW,KAAK,KAAK,KAAK,cAAc,CAAC,GAAG;AACjD,eAAW,WAAW,QAAQ,QAAQ,iCAAiC;AACvE,QAAI;AACF,YAAM,KAAK,SAAS,EAAE,KAAK,MAAM;AAAA,IACnC,SAAS,GAAG;AACV,UAAI,iBAAiB,QAAQ,yCAAyC;AAAA,IACxE;AAAA,EACF;AAEA,MAAI,eAAe,KAAK,QAAQ,UAAU,GAAG,IAAI,GAAG,MAAM,eAAe;AAC3E;AAEA,SAAS,sBAAsB;AAC7B,QAAM,UAAU,WAAA;AAChB,MAAI,CAAC,SAAS;AACZ,QAAI,iCAAiC,cAAc,QAAQ,eAAe;AAC1E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO,IAAIC,OAAAA,aAAa,OAAO;AACjC;AAGA,eAAe,WAAW,YAAoB;AAC5C,QAAM,eAAe,oBAAA;AACrB,QAAM,uBAAuB,GAC1B,YAAY,aAAa,IAAI,EAC7B,KAAK,CAAA,QAAO,IAAI,YAAA,MAAkB,WAAW,aAAa;AAC7D,MAAI,CAAC,sBAAsB;AACzB;AAAA,MACE,UAAU,UAAU;AAAA,IAAA;AAEtB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAMR,UAAS,MAAM,aAAa;AAAA,IAChC,KAAK,KAAK,aAAa,MAAM,oBAAoB;AAAA,EAAA;AAEnD,MAAI,CAACA,SAAQ;AACX,QAAI,UAAU,UAAU,kBAAkB;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAOA;AACT;AAGA,SAAS,aAAaA,SAAgD;AACpE,QAAM,YAAYA,QAAO,iBAAA,GAAoB;AAC7C,MAAI,CAAC,WAAW;AACd,QAAI,UAAUA,QAAO,QAAA,EAAU,MAAM,6BAA6B;AAClE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAe,WAAW,YAAoB,OAAO,OAAO;AAC1D,QAAMA,UAAS,MAAM,WAAW,UAAU;AAE1C,QAAM,YAAYA,QAAO,iBAAA,GAAoB,UAAU,CAAA;AACvD,QAAMS,UAAU,MAAMT,QAAO,QAAQ,UAAA,KAAgB,CAAA;AACrD,MAAI,MAAM;AACR,YAAQ,IAAI,KAAK,UAAUS,SAAQ,MAAM,CAAC,CAAC;AAAA,EAC7C,OAAO;AACL,eAAW,OAAOA,SAAQ;AACxB,UAAI,CAAC,UAAU,GAAG,EAAG;AACrB,YAAM,QAAQA,QAAO,GAAG;AACxB;AAAA,QACE,IAAI;AAAA,QACJ;AAAA,QACA,OAAO,UAAU,YACf,OAAO,UAAU,YACjB,OAAO,UAAU,YACf,MAAM,WAAW,SACjB,KAAK,UAAU,KAAK,EAAE;AAAA,MAAA;AAAA,IAE9B;AAAA,EACF;AACA,UAAQ,KAAA;AACV;AAEA,eAAe,UAAU,YAAoB,YAAoB,OAAO,OAAO;AAC7E,QAAMT,UAAS,MAAM,WAAW,UAAU;AAC1C,QAAM,YAAY,aAAaA,OAAM,EAAE,UAAU;AACjD,MAAI,cAAc,QAAW;AAC3B,QAAI,UAAU,WAAW,MAAM,WAAW;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAMS,UAAU,MAAMT,QAAO,QAAQ,UAAA,KAAgB,CAAA;AACrD,MAAI,MAAM;AACR,YAAQ,IAAI,KAAK,UAAUS,QAAO,UAAU,GAAG,MAAM,CAAC,CAAC;AAAA,EACzD,OAAO;AACL,QAAIA,QAAO,UAAU,CAAC;AAAA,EACxB;AACA,UAAQ,KAAA;AACV;AAEA,eAAe,UACb,YACA,YACA,aACA;AACA,QAAMT,UAAS,MAAM,WAAW,UAAU;AAC1C,QAAM,YAAY,aAAaA,OAAM,EAAE,UAAU;AACjD,MAAI,cAAc,QAAW;AAC3B,QAAI,UAAU,WAAW,MAAM,WAAW;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI;AACJ,UAAQ,UAAU,MAAA;AAAA,IAChB,KAAK;AACH,eAAS,gBAAgB;AACzB;AAAA,IACF,KAAK;AACH,eAAS,OAAO,WAAW;AAC3B,UAAI,MAAM,MAAM,GAAG;AACjB,YAAI,wBAAwB,YAAY,MAAM;AAC9C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA;AAAA,IACF,KAAK;AACH,eAAS;AACT;AAAA,IACF,KAAK;AACH,UAAI,CAAC,UAAU,QAAQ,SAAS,WAAW,GAAG;AAC5C;AAAA,UACE;AAAA,UACA,WAAW;AAAA,UACX;AAAA,UACA,UAAU,QAAQ,KAAK,IAAI,EAAE;AAAA,QAAA;AAE/B,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,eAAS;AACT;AAAA,IACF;AACE,UAAI,4CAA4C,UAAU,KAAK,IAAI;AACnE,cAAQ,KAAK,CAAC;AAAA,EAAA;AAGlB,QAAM,eAAgB,MAAMA,QAAO,QAAQ,UAAA,KAAgB,CAAA;AAC3D,eAAa,UAAU,IAAI;AAC3B,QAAMA,QAAO,QAAQ,UAAU,YAAY;AAC3C;AAAA,IACE;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACAA,QAAO,UAAU;AAAA,IACjB;AAAA,IACA,OAAO,WAAW;AAAA,EAAA;AAEpB,UAAQ,KAAA;AACV;AAEA,eAAe,gBAAgB,YAAoB,OAAgB;AACjE,QAAMA,UAAS,MAAM,WAAW,UAAU;AAC1C,MAAI,CAAC,OAAO;AACV,UAAM,EAAE,WAAW,MAAM,QAAQ;AAAA,MAC/B;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,MAAA;AAAA,IACX,CACD;AACD,QAAI,CAAC,QAAQ;AACX,UAAI,gBAAgB;AACpB,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACA,QAAMA,QAAO,QAAQ,WAAA;AACrB,QAAMA,QAAO,QAAQ,KAAA;AACrB,MAAI,+BAA+BA,QAAO,QAAA,EAAU,IAAI;AACxD,UAAQ,KAAA;AACV;AAEA,eAAe,YAAY,YAAoB,YAAoB;AACjE,QAAMA,UAAS,MAAM,WAAW,UAAU;AAC1C,QAAM,YAAY,aAAaA,OAAM,EAAE,UAAU;AACjD,MAAI,cAAc,QAAW;AAC3B,QAAI,UAAU,WAAW,MAAM,WAAW;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,eAAgB,MAAMA,QAAO,QAAQ,UAAA,KAAgB,CAAA;AAC3D,eAAa,UAAU,IAAIA,QAAO,QAAQ,iBAAA,EAAmB,UAAU;AACvE,QAAMA,QAAO,QAAQ,UAAU,YAAY;AAC3C;AAAA,IACE;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACAA,QAAO,UAAU;AAAA,IACjB;AAAA,IACA,aAAa,UAAU;AAAA,EAAA;AAEzB,UAAQ,KAAA;AACV;AAEA,MAAA,cAAe;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;;;"}