Commit Graph
53 Commits
Author SHA1 Message Date
bbassieandClaude Opus 5.5 d7fc3aaec4 Replace bootstrap methods with async factories
Controller.bootstrap and Host.bootstrap returned constructor arguments
that the caller had to spread into new Controller/Host, and
DatastoreProvider.bootstrap did the same for datastores. They are
replaced by Controller.fromConfig, Host.fromConfig and
KeyValueDatastore/SubscribableDatastore.fromProvider, which load the
data and return the finished instance.

Closes #1126

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 23:51:22 +00:00
Arvids Godjuks 28eb3a07e0 Remove obsolete 2.0 development warnings (#1078) 2026-10-14 22:24:55 +03:00
bbassieandClaude Opus 5.5 e455d17bb7 Write plugin versions while loading configs
The staging copy made by Config.set() went through the constructor, so
plugin migrations ran a second time on the live fields. A version-gated
migration was applied twice when setPluginVersions() changed the version.
Staging now copies the fields with update() instead.

A config saved without <plugin>.version got the running version as its
default, so setPluginVersions() saw no change and nothing saved the stamp.
The constructor now writes the registered plugin versions after the
migrations run and marks the config dirty when that changes a loaded value.
Controller.bootstrap() saves the instances that came out dirty, and
setPluginVersions() is gone.

Restructure the SyncHook and plugin config tests by method, and suggest the
controller config version for role migrations in the docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:37:03 +00:00
bbassieandClaude Opus 5.5 aec0fc7a1e Let plugins migrate the data core stores for them
Plugins had no way to update the config fields and permissions core stores
for them, so renaming inventory_sync needed migrations in core packages.

A plugin can now declare a migrationEntrypoint. It's loaded on the
controller and hosts before configs and roles are read, for every plugin in
the plugin list, and attaches handlers to sync hooks for the controller,
host and instance configs and roles. lib gets helpers to rename config
fields and permissions, and each config gets a hidden <plugin>.version field
set after load so migrations can tell which version saved the data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:33:27 +00:00
Danielv123 b411c5bef8 Fix running Clusterio from published packages
Since the move to ES modules and pnpm 12, packages installed from npm
fail to start:

- The package imports of @clusterio/lib point Node at TypeScript
  sources, which Node refuses to strip types from inside node_modules.
- The controller, host and ctl import their package.json from next to
  the compiled entrypoint, a copy pnpm leaves out of the package.
- ctl, host and web_ui have no .npmignore, so pnpm packs them using the
  repository .gitignore and leaves out nearly all of dist/.

Resolve the package imports to the compiled files at runtime while
keeping the sources for type checking, import package.json by package
name so it resolves to the real file, and add .npmignore files so pnpm
packs the same files as npm.
2026-10-11 13:18:09 +02:00
Hornwitser 2c52c265cf Require config files to be explicitly created (#1040)
The behaviour of creating the config file if it's missing while
convenient causes confusion and problems when the tools are run
in the wrong folder.  They end up creating a shadow installation
and misdirect the user with nonsensical error messages, instead
pointing to the real problem which is that the tool can't find
the configuration needed to actually run.

Require a config file to be present at startup and refuse to run if this
file is missing.  To support the odd use-case of creating the config
when missing a --create-config flag is added. To conveniently generate
a config file to edit out from the "config create" command is added.
2026-09-15 22:16:54 +02:00
Hornwitser 5df5af7ca8 Rename Ctl's usage of "control" to "ctl" (#1039)
Ctl ended up calling its main class for "Control" for historical
reasons, along with its config file and plugin entrypoint.

The plugin entrypoint was renamed to ctl in 808eda0513.  This
finishes that renaming by also renaming the main class, default config
file, config-control command, and main entrypoint.

The config-control command is renamed to config to be consistent with
the host and controller's config commands.

The term "control" is still kept in the config and message locations as
a common specifier for both ctl and web_ui.
2026-09-14 20:18:41 +02:00
bbassieandClaude Fable 5.1 87aa7b3b4c Require a token to scrape /metrics
The metrics endpoint fans out a gather to every connected host, so
anyone who could reach the controller could read cluster statistics and
put load on all hosts at will. Scraping now needs a user token holding
the new core.controller.metrics permission. The token is accepted via
Authorization: Bearer as well as X-Access-Token because Prometheus can
only send the former. Concurrent scrapes share one gather so hosts see
at most one metrics request at a time.

The three connection gauges in controller.ts now no-op before the
controller exists, like the other gauges there, so the endpoint can be
tested against the mock controller.

Closes #1009

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 22:28:43 +00:00
BastiaanandClaude Fable 5.1 d4b6df4f63 Create config files with mode 0o600 (#1017)
Config files hold the auth secret and tokens, so the default 0o644 lets
every user on the system read them. Config.save, the ctl config written
by the controller bootstrap, ctl host create-config and the config
migration in create now pass mode 0o600.

safeOutputFile also applies the mode to the temporary file it writes,
since writeFile only honours mode on creation and a leftover temporary
from a failed write would otherwise keep its old mode.

Closes #1005

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 01:49:14 +01:00
8c03ac15ab Define permissions on PluginDeclaration (#988)
Adds a permissions array to PluginDeclaration, a type-level Permissions
registry that plugins extend with module augmentation, and
registerPluginPermissions() called from all entrypoints. checkPermission
and the web UI hasPermission helpers now take PermissionName so typos are
compile errors. Core definitions move into a corePermissions array that
the interface derives its keys from.

Closes #987

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com>
2026-09-11 23:28:30 +01:00
Hornwitser 5dcaca4d0b Migrate to ECMAScript Modules
Migrate the usage of CommonJS specific code and imports to ESM.  Roughly
summarised this:
- Changes all require() calls to import statement or expressions.
- Changes usage of module.exports to export statements.
- Replaces require.resolve with import.meta.resolve.
- Replaces conditional imports with conditional subpath imports.
- Replaces module === require.main with import.meta.main.
- Adds the full filename with extention to all relative imports.
- Changes all usage of __dirname and __filename to their import.meta
  equivalents.
- Sets "type": "module" in package.json files.
- Removes usage of "use strict".
- Adds .ts an an alias of .js for the webpack build.

Due to differences in how require and import resolves files the plugin
entrypoints will have to include the filename and extension after this
migration in order to work.
2026-09-11 22:43:57 +02:00
Hornwitser d6dce12acc Use factory pattern for yargs
The ESM import of yargs does not support the singleton way of using
yargs, instead we have to call the yargs function to get a parser that
can be augmented with the options.

The .argv property has also been deprecated. Replace it with a call to
.parse() instead.
2026-09-11 19:51:15 +02:00
Hornwitser 71f78c14a3 Add command for copying static assets to a folder
This is useful in case the static assets are hosted by a separate web
server like Nginx, or for testing that the static_url option works as
intended.
2026-08-31 20:14:13 +02:00
Cooldude2606 e8cabb7196 Standardise shutdown signal guarding 2026-04-14 22:10:01 +01:00
Hornwitser 2e48b728dd Remove fs-extra and klaw (#882)
These packages are obsoleted by the promises API to the built-in Node fs
module.  The fs-extra package is also causing problems with broken APIs
that don't behave the same as Node's fs module, and throwing errors
without code properties on them.
2026-04-09 22:53:13 +02:00
Cooldude2606 4868ed2d63 Merge branch 'master' into feature/config-validation 2026-03-16 23:22:54 +00:00
Hornwitser 276c36b6e9 Throw error if lib is imported twice (#863)
The lib library was written with the assumption that there's only one
copy of it in the whole application and everything imports that one
copy.  Unfortunately there are quite a few circumstances were package
managers end up installing multiple copies of lib and then different
parts use different versions of the library.

This causes Clusterio to break with strange and hard to track down
errors.  Most notably permissions and link messages for a plugin may get
registered to one copy of lib while the controller uses a different copy
and thus does not see or register that what the plugin added exists.

Detect this condition when importing @clusterio/lib and throw an error
when it has been imported twice in order to prevent the broken
installation from causing future hard to debug issues.
2026-03-06 18:50:18 +01:00
Cooldude2606 014b18caf8 Fix type of controller.auth_secret 2026-03-04 21:02:39 +00:00
Cooldude2606 d05a529c52 Improve config field definition type 2026-03-03 22:22:59 +00:00
Cooldude2606andHornwitser 2235294c59 Refactor user and instance manager (#837)
* Refactor UserManager to use Datastore

* Rename lib.User to UserDetails also adds to/fromUserDetails

* Fix existing tests

* Add user class tests

* Add tests for finaliseUsers

* Move HostDetails to own file with tests

* Move InstanceDetails to its own file with tests

* Rename HostInfo and add tests

* Rename InstanceInfo and add tests

- Also changes the names of the host properties related to instances
- Also removes the need to specify the location of InstanceInfo

* Make json round trip test validate schema

* Add InstanceManager

* Fix lint errors

* Extra tests

* Add final test coverage

* Add one last test to InstanceManager

* Response to comments

* Use generator rather than return anonumous generator

Co-authored-by: Hornwitser <github@hornwitser.no>

* Fix lint issue with generator

---------

Co-authored-by: Hornwitser <github@hornwitser.no>
2026-03-01 23:04:37 +00:00
Cooldude2606 1228baa9a3 Move ensure default roles onto Role class 2026-02-07 01:27:59 +00:00
Cooldude2606 d48b731ea4 Add lockfile bypass 2026-01-08 22:48:00 +00:00
Cooldude2606 bccb6527a7 Add lock file for configs 2026-01-07 01:20:40 +00:00
Cooldude2606 00cf0f59ec Refuse to start controller with no users 2026-01-07 00:21:56 +00:00
Danielv123 7e2f10e842 Fix linting issues with new rules 2025-08-01 22:26:25 +00:00
Cooldude2606 a5bf8d92d9 Separate roles to their own file 2025-06-13 22:24:56 +01:00
Cooldude2606 515093abd2 Improve error message logged for config load error 2025-05-12 21:32:44 +01:00
Cooldude2606 726a3538c2 Move save and load into config class 2025-05-12 21:32:44 +01:00
Cooldude2606 17db53403a Move filepath into config class 2025-05-12 21:30:48 +01:00
Daniel 0adb45bba4 Merge pull request #758 from Cooldude2606/feature/pending-restart
Add indicators for host version mismatch and required restart
2025-05-11 14:14:39 +02:00
Cooldude2606 be071be8f2 Add recovery startup mode (#757)
* Add recovery startup mode

* Change error code to RecoveryMode
2025-05-10 21:33:45 +01:00
Cooldude2606 c120443657 Add checks for updated version on disk 2025-04-27 23:57:58 +01:00
Danielv123 636777d935 Add locally provided plugins by default 2024-11-25 12:22:16 +00:00
Cooldude2606 bdf02a5ea2 Made user ids case insensitive 2024-11-22 04:06:34 -08:00
Hornwitser a2ea2f2604 Merge branch 'master' into feature/datastore 2024-09-04 00:08:52 +02:00
Arvids Godjuks 55fcd90ed2 Fix bootstrap command missing type declaration for admin name
Lack of typing was resulting in admin name being serialized to storage as a number and breaking websocket communications protocol due to type mismatch: expected string, got number.

Fixes #536
2024-09-03 01:24:24 +03:00
Cooldude2606 609db31027 Add hosts, instances, systems 2024-05-22 16:39:22 +01:00
Hornwitser d7edae99c5 Add metrics for pending request
Track the number of requests currently awaiting a response from a
request handler both from interally issued requests and requests
forwarded from other parties.
2024-01-22 20:48:01 +01:00
Hornwitser 8884116ee9 Implement stop and restart of controller/hosts (#554)
Implement remotely initiated stopping and restarting of the controller
and hosts.  Restarting is implemented by exiting with a non-zero exit
code and relying on a process manager to start the procress again.  To
prevent accidentally trying to restart on a system that doesn't have a
process manager present the --can-restart command line option needs to
be passed to enable the restart operation.
2024-01-18 16:10:42 +01:00
Hornwitser e74065a493 Remove config groups
Refactor away the config group concept and simplyfy the way config
fields are defined.  Fields are defined directly as properties of the
static field fieldDefinitions on the class itself with a separate
interface to declare the types of fields.

This makes it possible to easily make accessing the config fields type
checked in a way that lets plugins extend the interfaces with their own
config options by adding additional fields to the interface via
declation merging.
2024-01-09 02:19:07 +01:00
Hornwitser 001db4befe Refactor config to JSON data class pattern
Refactor the Config and ConfigGroup classes to match the JSON data class
pattern with toJSON, toRemote and fromJSON methods replacing the load,
init, and serialize methods.  Since fromJSON requires extra information
the messages structures passes around the plain JSON representation of
the configs instead of serialising instances of the config classes
automatically.
2024-01-06 19:53:32 +01:00
Hornwitser 27af142a87 Remove silly support for async initial_value
This complicates the handling of configs for no good reason.
2024-01-06 19:49:35 +01:00
Hornwitser e453a80155 Refactor User and Role into data classes (#531)
Use the JSON data class pattern for User, Role, and PlayerStats and move
them into lib/src/data.  This means that User is purely data now and
can't reference role objects directly.  To make it possible easily check
permissions attached to roles and store data only visible on the
controller on user objects a ControllerUser type is introduced which is
linked with the UserManager and can therefore reference role objects
directly.

Resolves #525.
2023-12-02 01:41:43 +01:00
Hornwitser ab52cc35bf Provide controller resources at construction time
Load hosts, instances, mod packs, mods and users before constructing the
Controller instances.  This allows these resources to be correctly typed
as always available and prevents any possibility of save being initiated
on these resources before they are loaded.
2023-11-30 18:31:42 +01:00
Hornwitser 808eda0513 Move base plugins to their respective packages
Move BaseControllerPlugin to controller/src/BaseControllerPlugin.ts
Move BaseInstancePlugin to host/src/BaseInstancePlugin.ts
Move BaseControlPlugin to ctl/src/BaseCtlPlugin.ts
Move BaseWebPlugin to web_ui/src/BaseWebPlugin.ts

This solves the circular package dependency problem of the base plugins
needing types that are available only in the dependencies to lib.
2023-11-25 18:41:43 +01:00
Hornwitser 87e52b804e Convert JSON file indents to tabs
Be consistent with the usage of tabs as indents in all JSON files in the
project.  This makes it easier to configure editors to emit the right
indents when manually editing these files.
2023-11-25 18:19:15 +01:00
Hornwitser 142cf8a626 Fix log splitting not happening on UTC boundnary 2023-11-24 20:53:16 +01:00
Hornwitser 80e1904175 Fix bad typings left over from the migration 2023-11-19 04:50:07 +01:00
Hornwitser 7314dc99c8 Fix code style errors
Remove extra whitespace, use more consistent spacing, add missing
semicolons, using dangling commas, break up long lines, consistent
multiline operator placement, add missing JSDoc strings and so on.
2023-11-19 04:48:38 +01:00
Luciole 838170a9ff Port packages/web_ui to TypeScript (#508)
* .jsx to .tsx

* controller: tsc --build before webpack-cli

* Type Annotation

* disabled move into the <Input/> and <Checkbox/>

* cleanup debug left over

* documentation

* default ModPack

* modPackUpdateHandlers no undefined

* PluginInfo changes proposition

* PluginInfo changes proposition miss

* ModRecord & ModInfo feedback loop at const mods = [ ?

* ["connect", "drop", "resume", "close"] as const

* .tsx to .ts when possible
2023-09-02 14:51:35 +02:00