Build and minify the Web UI using swc instead of babel, tsc and terser.
This results in a significant speedup of the build process as it skips
checking types and uses native code to do the minification.
To prevent accidental type errors being introduced the TypeScript
compiler is still used to perform type checking on the Web UI files.
Due to peer dependency resolving shenanigans the swc/core package had to
be added to the workspace, controller and web_ui to avoid pnpm creating
a duplicate install of webpack that break the build.
Add back unqualified tsconfig.json files to each package that references
both the Node.js build and the browser build. This makes tsc --build
compile both builds when the variant to do is not specified.
Distinguish the Node.js build in the same way the browser build is with
the .node suffix to the tsconfig files it uses. This means
tsconfig.node outputs to dist/node and tsconfig.browser outputs to
dist/browser.
Use a separate folder for the TypeScript build for Node.js in the dist
folder. This makes each type of build consistently have its own output
folder instead of being interleaved with the Node.js build.
Use dist/browser as the output of the browser oriented TypeScript build
of packages instead of dist/web/build. This distinguishes it better
from the Web UI bundle which is put together with webpack.
Rename the config files for the browser build of modules to better
communicate that it's purpose is to compile code for a browser
environment rather than the Web UI in particular. This also aligns with
the "browser" option in package.json, the existing browser.ts entrypoint
in lib, and how the browser environment is typically referred to.
When the level of a technology changes either by setting level
directly or by setting researched to true, the saved progress of the
research is reset only if the technology is not the current research.
If during the initial synchronisation with the controller an instance
has progressed on a multi level research, it's the current research, and
the controller's level of that research is higher, then the level is set
to the higher level and the game keeps the progress. This in turn
results in all of the progress made on the previous level being added to
the higher level.
Fix by setting the progress to zero when changing the level or
researched status of a technology that's the active research.
Throw an error if an attempt is made to check for a permission that does
not exist in the Web UI to prevent future bad permission checks going
unnoticed.
Fix attempts to check for permissions that don't exist in the Web UI
that has gone unnoticed because the check still succeeds when the
account has the cluster admin permission.
Follow the same pattern as all the other subscribable lists by having a
separate .list and .subscribe permissions for saves. This also fixes
the save list not being visible due to a typo in the permission in the
Web UI.
Without a unique per page key set react will try to reuse the existing
state and components of the previous page and update them to match the
new page. This causes unexpected behaviour as components get turned
into into a Frankenstein abomination of the previous page and the
current one fused into one.
Fix by setting a key on the top level fragment of the page which in turn
forces React to re-render the whole page whenever the user switches to
another page.
If the value in a subscribed list is updated while the updatedAtMs
timestamp is kept the same then the caching logic of the subscription
system will cause updates to be silently dropped. Log a warning if a
subscriber catches this happening to help tracking down such cases.
Always send the instance details update when an instance is reassigned,
not just when it is unassigned. The idea for not sending an update when
assigned to a host was that the host would send an update on the status
that in turn updates the instance details. However this is not actually
the case; when a stopped instance is reassigned its status does not
change so the update is ignored.
Set the save's updatedAtMs timestamp when clearing the save list of a
reassigned or deleted instance. This fixes the Web UI not updating the
saves list to remove the saves when an instance is reassigned.
If a link is closed while the prepareDisconnect action is in progress
the link will still try to signal the disconnect ready over the socket
when the prepareDisconnect action completes, which throws due to the
socket no longer being present. This error is not caught due to the
catch happening before the finally on the promise and triggers an
unhandled rejection.
Fix by rearranging the finally to come before the catch on the promise
so that errors are always handled, and checking that the link still has
a session before attempting to send the disconnect ready signal.
When using .finally on a promise a new promise is created which calls
the handler passed to it when the the original promise is resolved or
rejected, and resolves or rejects with same value as the original
promise. This means if the rejection of the new promise that was
created by finally is not handled then an unhandled promise rejection
will be raised.
Fix by making sure the promise rejection from the finally promise
created in subspace_storage's handleUpdateStorageEvent is properly
handled.
When messages were forwarded they were sent using the low level
connector .send method which accepts a message and sends it over the
link. This method sends the message as is with no modification which
means that at no point during the forwarding logic was the message
sequence number that originated from Link A renumbered to the correct
sequence number to send out on Link B which it was forwarded on.
This in turn caused the logic which drops acked messages from the send
buffer to break which in turn meant the resume could cause duplication
of message and/or messages to be lost. With enough duplicated messages
the resume of one connection could cause other connections to drop and
also initiate resume.
Fix by renumbering the sequence on forwarded messages. In the future
the sequences sent and received should also be checked to make sure this
kind of problem does not happen again, this is not done here because
partially updating a running cluster with sequence problems to one that
checks and enforces sequences numbers will be problematic.
When host and instance id in Address was reordered in 1e66f11 the
toString method Address was updated to account for this. Fix toString
showing host addresses as being instance addresses and vice versa.
When a plugin broadcasts an event to instances there may be hosts and
instances in the cluster which does not have the plugin loaded. This
would cause an error to be logged for every instance which does not have
the plugin loaded.
Filter out broadcast events sent to hosts and instances such that
instances and hosts that does not have the event do not received them.
If during the startup of an instance the Factorio server is started up
to create a new save and the host shutdown in initiated then the
instance will be commanded to stop while the FactorioServer state is
"create". This was was not handled by Instance.stop leaving the
child_process running after the host is done shutting down.
Kill the FactorioServer on stop if the current state of it is stopping
or create to make sure the server actually stops.
When a request is forwarded from a virtual link to a WebSocket link as
is the case when an instance sends a request to the controller the
origin for the request is a virtual link. Handle this case in
_clearPendingRequests instead of throwing an assertion error.
Track the number of requests currently awaiting a response from a
request handler both from interally issued requests and requests
forwarded from other parties.
Fix installer incorrectly exiting with a conflicting options errors when
the --no-download-headless option was used in conjunction with the
--factorio-dir option.
If a plugin only has entrypoints at the controller level the config will
skip adding a "load_plugin" config option for the given plugin to avoid
making options that do nothing. If such a plugin is added to a host it
will still reach loadPlugin which in turn tries to check the load_plugin
config and throw an error on startup due the field being missing.
Skip trying to load plugins without an entrypoint at the instance or
host level in hosts before checking the load_plugin config field.
Add a note about double checking which version of Node.js is installed
to avoid accidentally updating on an outdated version, and fix migrate
arguments.