Allows the `checkLatestVersion` function in the `VersionService` to
accept an optional `instanceInfo` parameter. If provided, and if the
promise returns a value that is truthy, then it will add `instanceInfo`
to the versionPayload.
The license key may not contain a plan or a customer name, and while it
definitely won't contain a client id, it has been requested that we
report `self-hosted` as the client ID (will be handled in enterprise).
Adding a second, optional parameter seemed to be the most backwards
compatible way of doing this rather than changing the established method
/ callback types.
## About the changes
Properly awaits all submitted promises, preventing the node's main
process from seeing rejected & unawaited promises.
What's going on?
- The bulk metrics handler pushes `registerBackendClient` promises into
promises.
- The next step (`clientMetricsEnvBulkSchema.validateAsync`) throws for
invalid metrics (e.g., `appName: null`), so we jump to catch and return
400.
- Because the code never reaches `Promise.all(...)`, the previously
spawned promises are never awaited. Node later detects the rejected
`registerBackendClient` promise as an **unhandled rejection** and
crashes the process. If that promise hadn’t been rejected, there’d be no
crash, but with invalid input, it does reject.
- **Fix:** always await the spawned tasks (using `Promise.allSettled`)
so every rejection is observed, even when validation later throws.
The `create` and `update` role methods used to blindly accept any
incoming permissions, but if the permissions don't exist in the
database, then the database would throw, yielding a 500 error to the
user.
To fix this, we can validate that all the permissions exist before we
try to add the incoming permissions.
The http error only manifests in enterprise, but the fix requires
modifying the access service. Therefore, I've added the tests to the
access service too, such that if you break something, then you don't
need to wait for it to propagate to enterprise.
---------
Co-authored-by: Gastón Fournier <gaston@getunleash.io>
TypeScript throws `TS7056` because the schema object becomes too large
for the compiler to fully serialize when using deep literal inference.
Splitting the components object and explicitly reconstructing the type
prevents the error while preserving correct type inference.
Adds a test to ensure that the `getAll` method of the flag resolver
doesn't return the disabled variant if a flag is defined as a boolean in
the settings.
We have some places in the UI where we check `if
(uiConfig.flags.<flagname>) {...}`. If one of these flags were suddenly
returned as the disabled variant instead of `false`, then it'd be
impossible to turn it off.
As such, to maintain backwards compatibility and adhere to the principle
of least surprise, I'd like to add this test to ensure this doesn't
change going forward.
Fixes a bug / uncovered edge case in the flag resolver in Unleash:
If a local experiment was defined as false (the typical default value),
then that flag could only ever be returned as a boolean from the
`ui-config` endpoint. In other words, even if the external resolver has
a variant for that flag, the UI would never get the variant.
The fix is to not just check `isEnabled` for false flags, but instead:
- use `getVariant`
- then check `variant.enabled` (in which case we have a variant and can
return it)
- else check `variant.feature_enabled`, falling back to `isEnabled` only
if `feature_enabled` is null/undefined.
Updates the maintenance mode banner to accept string variants, allowing
for custom maintenance mode messages.
Because the banner is almost the same as the existing banner component
we have, we can simplify the impl and just reuse the existing banner
instead. The one difference is that the maintenance mode banner used to
be taller. However, after talking to UX, we agreed that the banner
should be the same size, anyway.
<img width="1552" height="120" alt="image"
src="https://github.com/user-attachments/assets/fc9dc8ad-26ba-411a-846e-a79e1b855f37"
/>