Values in the assetsByChunkName object are arrays not strings. This
caused the dev mode to fail after 2f4e0c4418 added an additional step
filtering out the static/ prefix from what it expected to be a string.
Add option in the controller config to set where static assets are
loaded from in order to support deployments where the static assets are
server via a CDN while the API is directly accessed.
This is useful because some CDNs put low limits on how large requests
bodies can be, which causes issues with uploading large mods and saves.
staticRoot was set to the same value as webRoot, so the static/ prefix
ended up scattered across consumers: index.html relied on the manifest
path containing it, the export stores hardcoded `${staticRoot}static/`,
and bootstrap loaded plugin bundles from webRoot instead. Now staticRoot
is `${webRoot}static/` and the controller strips the static/ prefix from
bundle paths before handing them to the page and to /api/plugins.
Plugins that fetch assets with `${staticRoot}static/...` need to drop the
static/ part.
Fixes#980
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cooldude's GameVersion brand was disjoint from the clean version types in
both directions, forcing safeVersion/safeFactorioVersion companions and
breaking widening from FullVersion at file-name call sites.
Make GameVersion a plain string alias: the raw, un-normalised version as the
game reads it. The stricter template-literal types (FullVersion,
MajorMinorVersion, PartialVersion) now widen into it for free, while a
GameVersion still can't be used where a normalised version is required
without going through normaliseGameVersion/integerGameVersion. Runtime
validation stays in GameVersionSchema.
- Drop safeVersion/safeFactorioVersion; ModInfo.version stays raw (verbatim so
it matches the mod's file name), integerVersion normalises via the new
integerGameVersion. factorioVersion reverts to a normalised MajorMinorVersion
since it is never part of a file name.
- ModRecord.version becomes a GameVersion so mod packs round-trip the exact
file-name version.
- ModVersionEquality.testVersion / ModVersionRange.testVersion accept a raw
GameVersion and normalise it; the equality bound stays strictly validated.
- Migration only pads clean partial versions; raw versions are kept verbatim.
- Cover the leading-zeros case: version kept verbatim in the file name while
comparing equal to its normalised form.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
An instance's factorio.version can now target a release channel such as
"stable" or "experimental" (any key from factorio.com/api/latest-releases)
in addition to "latest" and specific X.Y / X.Y.Z versions.
The controller proxies the latest-releases API through a ValueCache and
persists the last successful response to latest-releases.json, serving that
copy when the API is unreachable. On instance start the host resolves a
channel to the concrete version it points to and feeds it into the existing
checkForUpdates/findVersion path, so a channel auto-installs and runs like a
pinned version. The version selector in the web UI lists the available
channels alongside "latest".
Also clarifies the host log/error when a newer version cannot be downloaded
automatically because the host uses a direct (single-version) Factorio
install rather than a versioned directory.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
If an error occurs trying to fetch the list of Factorio versions log a
warning and then return an empty list instead of preventing the system
from operating.
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.
* 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>
* Add ModDependency and version types
* Add warnings for mod dependencies
* Add warning for wrong factorio version
* Add fix issues button
* Add automatic dependency resolution and download
* Add abilty to check for updates
* Add extra test coverage
* One extra test
* Fix copy paste error
* Template type for load plugin config
* Add plugin update checking
* Add restart icon to instance list
* Add tests
* Log package name when failing to read package json
* Event types for controller
* Clean up ctl event emitters
* Event types for server
* Event types for lib
* Remove TypedEventEmitter
* Event types for webui
* Fix compile issues
* Small cleanup of connectors
If only the config of an instance is updated the dirty flag of the
instance is not set, which results in changes being discarded when the
controller shuts down afterwards.
Fix by always triggering the update logic when an instance field is
changed.
Add config entries to controller and host for the Factorio username and
token to use when talking to the Factorio APIs. If set an username and
token is not set in factorio.settings then these settings are used,
making it easy to configure one set of credentials for a cluster/host.
For running more public provide your own hardware clusters, there's an
option to disable controller sharing the credential with the hosts so
that each host have to set their own credentials.
When passing methods around they lose their binding to this, which means
the fromJSON methods no longer has this be their class. Fix by binding
the methods to the class they belong to before passing them on to the
datastore.
Remove some assumptions that prevent subscription listeners from working on an
instance. This means allowing the host to forward the event from the instance
to the controller; correctly storing subscription listeners by address rather
than by connection; and a bunch of network and event stuff to correctly clean up
a listener.
Remove the assumption that all subscriptions events contains the updates
property. This meant fixing inconsistent types; always checking if the property
existed; fixing lots of the tests that made incorrect assumptions.
Minior fixes:
- Fix double firing of listener callbacks on first connection.
- Fix synced being set to true too early on first connection.
- Fix edge case interaction between last response and last snapshot for values
with updated set as 0.
Also change the the output made during the start of tests to indicate something
is happening when start up is slow and allow for silent testing to reduce the
amount of text output to the console.