Update babel-eslint to the latest version 🚀 - #421
Closed
greenkeeper[bot] wants to merge 1 commit into
Closed
Conversation
7 tasks
diegolmello
added a commit
that referenced
this pull request
Aug 31, 2026
diegolmello
added a commit
that referenced
this pull request
Sep 2, 2026
* chore: update @rocket.chat/sdk to mobile branch HEAD
Bump the SDK from b6d2b3f to 1e16344. The mobile fork now ships the
reconnect/probe/media-subscription fixes the app previously applied as a
patch, so drop @rocket.chat+sdk+1.3.3-mobile.patch.
Declare the tiny-events module the SDK source depends on, and update the
DDP driver tests to the SDK's new error contract.
* test: integration-test the app against the real SDK lib
Drive connect/login/streams, RoomSubscription, socket recovery, and accept-after-reconnect through the real @rocket.chat/sdk DDPDriver/Socket/REST client, replacing SDK-internal unit tests. Rewrite the SDK's dynamic import to a require in the test env only.
* chore: bump @rocket.chat/sdk to mobile HEAD 4202408
Upstream renamed DDPDriver (lib/drivers/ddp) to Driver (lib/drivers/driver); update the SDK integration tests to match.
* chore: bump @rocket.chat/sdk to mobile HEAD and drop local module shims
Remove the '@rocket.chat/sdk' and 'tiny-events' declare-module shims from
externalModules.d.ts now that the SDK ships its own types, and align the app
with the real SDK typings.
* fix: address review — await voip listener, filter undefined upload headers, declare babel plugin
* chore: bump @rocket.chat/sdk to mobile HEAD 383e457b and drop sdk client shim
* fix: remove unreachable ping-age branch in classifySocketHealth
`ddp.connected` already folds in the ping-age test — Socket.connected is
`transportOpen && alive()`, and `alive()` is `now - lastPing <= config.ping * 2`,
the same multiplier `pingInterval * 2` used here. A connected socket therefore
never has a stale ping, so the second branch could not run.
Drop it, and drop the three unit tests that fed the mock `connected: true`
alongside a stale lastPing — a state the real driver cannot produce.
* fix(login): surface a failure instead of hanging on a missing login result
login() refused nothing when currentLogin.result was absent, returning undefined,
and loginTOTP wrapped its body in a hand-built promise whose success branch had no
else. A missing result therefore settled neither way and the login screen spun
forever with no error and no log entry.
login() now throws on a missing result and returns Promise<ILoggedUser>, and
loginTOTP is a plain async function, so every login outcome ends in a logged-in
user or a visible error.
* fix(upload): refuse an upload without auth headers
The upload helper filtered absent headers out of the request before sending, which
dropped the session's auth headers along with the optional ones and sent an
unauthenticated request that came back as an opaque server rejection.
FileUpload now refuses to build the request at all when the auth headers are
missing, before any network work, so all three upload call sites fail loudly
through their existing error surfacing.
* fix(2fa): report a cancelled two-factor prompt as a cancellation
Both request paths reported a dismissed two-factor prompt as a successful response
with an empty body, so callers could not tell a deliberate cancellation from a
server returning nothing.
twoFactor() now rejects with TwoFactorCancelledError, and sdk post() and
methodCall() propagate it instead of resolving an empty object. isTwoFactorCancelled
is the guard callers test against. The error lives in its own module so error
reporting can import the guard without pulling in the prompt component.
* fix(2fa): stop reporting a deliberate cancellation as an error
Now that a dismissed two-factor prompt rejects, the paths that can raise one would
report the person's own choice as a failure. Cancelling is a choice, not an error.
Error reporting and the alert helpers ignore the cancellation centrally, and each
two-factor-gated call site treats it as a no-op: profile and username changes,
account deletion, logging out other locations, password change, and the two
encryption key resets. Cancellation is recognised only through isTwoFactorCancelled,
never by matching a message. Genuine failures report exactly as before.
The login path deliberately keeps showing an error, otherwise the login screen
would silently spin again.
* fix: settle the promises that could strand a caller
An audit of every hand-built promise in app/ found three that could end without
settling, leaving a caller waiting forever with no error and no timeout.
RoomInfoView's createDirect did nothing when the request reported failure, so the
Message button died silently; it is now a plain async function that throws.
getRoles resolved only inside its non-empty branch, so an empty roles list stalled
the login saga's roles fork. An overlapping two-factor request overwrote the open
prompt's callbacks and stranded the first caller, which is now cancelled with the
existing cancellation error.
Every other hand-built promise was read and settles on all paths.
* chore: drop a comment describing the removed empty two-factor response
e2eResetOwnKey documented returning {} when TOTP is enabled. That response no
longer exists — a cancelled prompt now rejects.
* fix(2fa): cover the cancellation paths that bypass central suppression
Three two-factor-gated paths still reported a deliberate cancellation, because each
one loses the error before it reaches the shared error reporting.
The E2E encryption password change caught into a hardcoded message. The avatar
helper re-wrapped every unrecognised error into a generic translated one, which
destroyed the cancellation's identity; it now rethrows a cancellation untouched.
The login saga updated custom fields after dispatching loginSuccess, so cancelling
there marked an already-successful login as failed and dropped the fields.
* fix(upload): validate auth headers when the upload is sent
Asserting in the constructor threw before the caller could store the
instance in its upload queue, so sendFileMessage and sendFileMessageV2
read the missing queue entry as a user cancellation and swallowed the
error instead of persisting and rethrowing it.
* fix(2fa): stop alerting when the avatar prompt is cancelled
The view reports failures through showErrorAlert, which carries no
cancellation guard, so dismissing the two-factor prompt during an avatar
change still raised an alert.
* chore: adopt the SDK's login types and test against the real lib (#7582)
* fix(types): describe the login payloads and result the app actually sends
Adopt the login types from @rocket.chat/sdk (bumped to mobile HEAD
176bdfe4) and delete the two casts that stood in for them.
`toLoginResult` and `toSdkCredentials` converted nothing. The second one
compiled only by coincidence: the SDK's old flat `ICredentials` declares
`password` and `username` as required, so every login — saml, cas, apple,
oauth, resume — was typed as if it carried both.
- `ICredentials` is now the SDK's `ILoginCredentials` union, so each
producer builds the member it means and the guards land where the
information exists.
- `ILoggedUser.username` is optional: a user who registered without
choosing one has none, which `isRegisterUser` already assumed.
- Apple sends `{}` rather than `null` for `fullName`. Apple returns null
on every sign-in after the first and the server destructures it
unguarded, so repeat Apple logins failed with a generic error.
- `parseSamlOrCasRedirect` returns null instead of a payload with no
credential token, which is a login the server cannot complete.
- The 2FA retry always normalizes to `{ user, password, code }`. It used
to keep the ldap/crowd shape when the server predated 3.9.0, and
`compareServerVersion` reads an absent version as "older", so that
branch also ran whenever the version was not yet known — sending a
top-level `code` that the server's 2FA gate ignores.
The SDK also renamed the client's realtime field to `driver` and the
driver's socket to `socket`, and `Driver.subscribe` now declares
`eventname` before its rest args; `subscribe` keeps it optional because
`activeUsers` subscribes without one.
* refactor: keep the login status pass-through and name the credentials union
The status mapping defaulted an absent or unrecognised status to
'offline'. Nothing did that before — the old cast declared `status`
required and assigned the server's value straight through — so restore
the pass-through and leave `ILoggedUser.status` as it was. Whether that
field should be optional is a separate question with its own fallout in
StatusView.
`ICredentials` already named a local interface in actions/login.ts and a
different type in the SDK, so the union goes by its own name instead.
* fix: report a missing Apple identity token instead of throwing into the catch
The guard threw from inside a catch that only fires the failure event, so
it read as error handling but produced nothing — and it was
indistinguishable from the user dismissing the Apple dialog, which is why
that catch is bare.
* test: share the SDK integration scaffolding across the four suites
Each integration test carried its own copy of the mock connection, the
DDP frame helpers, and the collection/store builders. Move them into
app/lib/testUtils/sdkIntegration.ts and rename WireFrame to DdpMessage.
Jest mock registration stays per file and delegates to the shared
MockConnection through jest.requireActual so hoisting rules hold.
* refactor: finish the integration-helper sharing and review nits
Move buildConnectedDriver, addMediaSubs, backdateLastPing and
stopAnsweringFrames into the shared module, prefix its interfaces with
the project I, restore the 2FA code-clearing rationale, and give the
user-presence listener its typed message shape back via the app
wrapper, whose callback type accepts it.
* refactor: name the wire frames, trim a version-fragile comment, flatten a fallback
eventname to eventName in the subscribe wrapper, data to frame in the
shared mock connection, drop the alive() formula quote from the socket
health rationale, and spell out the preferred/fallback chain in
getUserDisplayName.
* refactor: drop the vocabulary footer and type the presence listener
The exported names already carry the terms, and the wrapper's return
type describes the listener promise on its own.
* fix: keep mute working without a username and drop dead SAML fallback
* chore: update @rocket.chat/sdk to mobile HEAD (#7583)
* chore: update @rocket.chat/sdk to mobile HEAD
The client exposes the realtime driver as `driver` instead of `ddp`, and
`currentLogin.result` is typed as the login payload the SDK returns rather
than the response envelope. `subscribeRaw` takes a name and params, so the
wrapper forwards them by position.
* docs: name the DDP Subscription and keep it apart from Subscription
A Subscription is a membership record; a DDP Subscription is a live feed on
Meteor Connect whose id the SDK derives from its stream and parameters.
* chore: narrow subscribeSettings and drop its unused SDK type import (#7584)
* test: use the app's own TDriver instead of reaching into SDK internals (#7585)
socketHealth.test.ts imported the Driver type from a deep path inside
@rocket.chat/sdk to describe a value whose type the app already exports.
TDriver is derived from the public client and is the exact parameter type
of the function under test, so the import bought nothing.
The two remaining deep reaches stay: they need the Driver class at
runtime, and the SDK root exports only settings and Rocketchat, so no
public route exists.
Verified by asserting Driver, TDriver and the function's parameter type
are mutually identical under tsc, with a deliberately falsified control
to confirm the check could fail.
* chore: remove lint suppressions for a disabled rule (#7586)
* chore: remove lint suppressions for a disabled rule
* chore: reach the SDK driver through the package root in tests
* chore: bump @rocket.chat/sdk to mobile HEAD b6453cc3
* test: cover multi-workspace switching (#7590)
* chore(e2e): trigger server-switch tests on switch-path changes
* test(login): cover switch cancelling the login bootstrap
* test(logout): cover removeServerData key scoping
* test(selectServer): cover target-workspace user resolution and failure invariant
* test(deepLinking): cover unknown host handing off to the add-server flow
* test(selectServer): guard the redundant select against the real SDK host
* test(selectServer): cover the offline version fallback
* test(login): cancel the saga task after each case
* test: share the saga store helper and tighten the fallback assertions
* test: finish the shared saga store migration and cancel every saga task
* test: own the saga task lifecycle in the shared helper
* test: tighten the shared helper types and the suite setup
* test: declare the cleared keys before use and restore the spied emitter
* test(logout): pin the deliberate certificate retention
* test: drop the redundant flushes and the unused store preload
flushSagaMicrotasks now drains twenty passes, so the back-to-back calls
inherited from the two-pass version are no-ops. createRecordingStore's
preloadedState had no callers.
* test: name the recorded actions for what they are
* test: annotate the test helper return types
* fix: server version recorded as undefined when falling back to another workspace (#7593)
* fix(server): use the fallback workspace's recorded version
The three auto-pick-another-workspace paths read `.version` off the record id
string, so `selectServerRequest` always received `undefined`. Online the
`/info` re-fetch masks it; when that re-fetch fails the stored version is
undefined and every `compareServerVersion` gate silently takes the legacy
branch.
* test: clean up the preferences the fallback test writes
* fix(logout): keep other workspaces reachable after a forced logout (#7591)
* fix(logout): keep other workspaces reachable after a forced logout
The forcedByServer branch of handleLogout emitted the NewServer event
without seeding previousServer, and serverFinishAdd had already nulled
it on login. NewServerView gates its close button, its Android back
handler and its layout on previousServer, so the user landed on a
header-less screen with no way back to workspaces they were still
logged in to.
Seed previousServer with the first remaining server that still holds a
token — the same predicate the non-forced branch already uses. The
logged-out server itself is not a valid target: logout() destroys its
record, token and database, so close() would find nothing and
useConnectServer would skip its disconnect. When no other server is
logged in, previousServer stays null and the screen correctly offers no
way out.
* test: move the forced-logout test onto the shared saga store harness
* refactor(logout): collapse the duplicated logged-in-server lookup and assert previousServer directly
handleLogout's non-forced branch hand-rolled the same 'first server that
still holds a token' scan the new findLoggedInServer already performs, so
it now calls the helper. selectServerRequest loses its second argument,
which was always undefined because newServer was a string id.
The forced-logout tests now assert the previousServer the view reads
rather than the SERVER.INIT_ADD action that sets it.
* fix(logout): pass the real server version when switching after a logout
selectServerRequest declares version as required, and the reducer stores
it, so omitting it left an offline switch landing with version undefined.
findLoggedInServer already returns the record, so the value is at hand.
* refactor(logout): look the remaining server up once for both logout branches
---------
Co-authored-by: Diego Mello <diego.mello@rocket.chat>
* fix: give every saga exit a user-facing root (#7592)
* fix: give every saga exit a terminal UI root
restore() and handleShareExtension() each had an early exit that pushed no
root-changing action. APP.START is the only thing that hides the boot splash
and the only thing that moves the root off a loading value, so those exits
stranded the app on a loading root with no recovery.
The un-raced take(LOGIN.SUCCESS) in handleShareExtension had the same effect
from a far more likely cause: SERVER.SELECT_FAILURE is handled only by the
server reducer and never touches app.root, so a failed connect left the take
waiting forever. It now races the two failure actions that selectServer and
login actually emit.
No timeout is added to the race. selectServer's catch always emits
selectServerFailure, so the failure modes are covered by action, and a bare
timer here would re-introduce the regression recorded at login.js:490.
* test: name the saga exit assertions after user-facing roots
* fix: close the remaining saga exits that skip a user-facing root
restore()'s other-logged-in-server branch passed the server id where a
record was expected, so selectServerRequest always received an undefined
version, and its return skipped appReady and the pending push handling.
handleShareExtension's race missed LOGOUT, which login.js emits instead of
LOGIN.FAILURE for logged-out-by-server, expired-token, and 401-with-user,
and its body was unguarded, so a throw from localAuthenticate or
getServerById left the share sheet on the loading root.
* fix: return to the server list when selecting a server fails from a loading root
SERVER.SELECT_FAILURE only reaches reducers/server.ts, which never touches
app.root, so restore()'s two selectServerRequest exits left the app on a
loading root when the switch failed. handleSelectServer's catch now falls
back to ROOT_OUTSIDE from the loading roots only, leaving inside and
share-extension roots as they were.
restore()'s other-server branch becomes a find, dropping the reuse of
userId as a did-we-select flag.
* fix: deliver the pending push notification instead of throwing into the boot catch
The inner const shadowed the payload with removeItem's undefined result, so
JSON.parse threw, restore()'s catch dispatched ROOT_OUTSIDE over the server
it had just selected, and the notification was dropped.
* fix: dispatch the pending push notification deep link
call() built the OPEN_VIDEO_CONF action and discarded it, so the deepLinking
watcher never ran. put() dispatches it, and a parse guard keeps a malformed
stored payload from throwing into restore()'s catch and overriding the server
it had just selected.
* refactor: userId is no longer reassigned in restore
* fix: drop the pending push notification when the boot lands outside
The push handling now runs only when restore() reached a server, so a stored
OPEN_VIDEO_CONF payload is cleared rather than dispatched into a session that
does not exist. Adds coverage for the malformed-payload guard.
* refactor: gate the push notification on the restored server, not the root
Reading state.app.root after appReady only happened to be correct: on the
selectServerRequest branches the connect is async, so the gate passed by
timing. serverToRestore returns the record the branch resolved, so the push
is gated on the branch actually taken.
* refactor: let serverToRestore resolve the stored token itself
The userId argument only ever carried a value the generator already reads for
every other server. All three branches now return null rather than a mix of
null and undefined. Covers the no-stored-server branch.
* test: cover both no-token exits and name the token check
isLoggedIn states the token lookup once for the guard and the find predicate.
Resets the servers collection mock between cases so the no-stored-server test
pins its own guard rather than a leaked mock.
* fix: fall back to the server list from any root that is not user-facing
At cold boot `app.root` is `undefined`, not `ROOT_LOADING` — nothing sets
a loading root on that path, so the failed-switch guard never fired where
the defect actually lands and `AppContainer` matched no navigator group.
Gate on the roots worth keeping instead of the ones worth replacing.
* test: cover the background/foreground socket resume path (#7589)
* test: cover the background/foreground socket resume path
Adds the AppState enhancer unit test and three real-SDK integration
scenarios for the foreground resume path: a silently dead socket that
reopens after a failed round trip, an actually closed transport that
reconnects and resumes the session, and a healthy socket that is left
alone.
* test: share the websocket mock and prove foreground drives the reconnect
* test: make the foreground-resume suite prove what it claims
Complete the resume-login round trip in the mock harness so the login
actually succeeds and the scenarios assert the resumed user, drop the
vacuous ordering and app-state assertions, and cover the foreground and
background guards plus the session save and away-presence update.
* test: drop the arbitrary sleep and the assertion that could not fail
The resume scenarios waited a fixed 100ms for the login round trip, and closed
by asserting isAuthenticated, which openSignedInSocket had already set. The wait
is now a bounded drain of the pending timer queue, and the surviving assertion is
the post-reset loginSuccess payload.
Adds the boot-time app-state dispatch the middleware suite previously discarded,
reuses the shared makeCollection and a shared latestConnection, and reverts the
socketHealth index-to-helper churn.
* test: wait for the resume to land instead of a fixed number of rounds
settle() stopped early only when every timer had drained, which never happens
on a connected socket - the SDK keeps its ping interval alive - so it always ran
its full round count and was the arbitrary wait it replaced. settleUntil() takes
the condition each call site is actually waiting for and keeps the round count as
a cap.
Also uses latestConnection consistently, names the app-state helper after what it
boots, and reads action types through one helper.
* test: name the quiet boot instead of asserting it inside a helper
bootMiddlewareFromUnknownState asserted a silent boot behind a name that only
promised to boot. Booting now always runs the boot timer, and the quiet case is
a test of its own.
* test: annotate the return types of the new test helpers
* test: state the boot input in the test that depends on it
* fix: make sdk.current nullable and guard its call sites (#7587)
* fix: make sdk.current nullable and guard its call sites
`Sdk.current` was declared non-nullable while `disconnect()` assigned null
behind a `@ts-expect-error`, so the compiler could not see the absent client.
Typing it honestly surfaced 30 unchecked sites across 7 files, including a
guard in `subscribeRooms` that tested the always-truthy singleton instead of
the field that goes null.
- `sdk` is `Rocketchat | null`; the wrapper's own methods read a private
`activeSdk` getter that throws when the client is absent
- `del` and `logout` join the wrapper, so their call sites stop reaching
through `current`; `push.token` gains its DELETE operation
- `connect()` uses the client `initialize()` returns instead of re-reading
the global 13 times
- lifecycle-straddling sites guard and return early; `login()` throws, since
its caller resolves on a truthy result only and would otherwise hang
* refactor: close the Sdk facade and drop sdk.current
`current` exposed the wrapped `Rocketchat`, so callers reached through it
into SDK internals — `client.client.host` for the connected host, `.driver`
for the socket handle — and every one of them had to repeat the nullability
guard the facade already owns.
- the facade gains `host`, `currentLogin`, `driver` and `isInitialized`,
which read the live client and return null when there is none, plus
`login()`, `abort()` and `subscribeNotifyUser()` that delegate through
`activeSdk`
- `current` is gone; every call site keeps its existing semantics, silent
return, early return or throw alike
- `login()` captures the client once and returns its `currentLogin`, so a
disconnect racing a login cannot turn a success into a missing result
- the host comparisons in `rooms.ts` and `selectServer.ts` still read the
live client rather than redux, since redux switches servers while the
previous socket is still delivering messages
* fix: drop stream frames and skip logout when the client is absent
* refactor: make the absent-client outcome explicit at each guard
* test: tighten the host-guard assertions
* fix: forget the cached push tokens even with no client to delete them from
* fix: forget the cached push tokens unconditionally
* fix: forget the cached push tokens only when a device token exists
* fix: drop media signals produced after the client is gone
* refactor: ask for client presence through a single predicate
* test: build driver-shaped doubles from the shared SDK harness
* test: cover the absent-client logout and the matching-host frame
* refactor: name the absent connection in the triggerAction failure
The guard now also covers a missing host, so the message says so. Drops the invented host default from the SDK test double, which no test reads.
* refactor: name the facade predicate for what it reports
The client is dropped on disconnect, so the predicate is not a one-shot init flag; hasClient says what the six call sites read it for and stops it reading like mediaSession.isInitialized().
* test: drop the sdk double's getter for a removed property
* test: drop the unreachable rejection from the media-signal double
* refactor: keep the sdk client and its driver behind the facade
initialize() returned the Rocketchat client, so connect.ts held its own
reference and bypassed the facade for connect() and nine onStreamData
registrations. It now returns void and the facade owns connect().
driver was typed as the whole vendor Rocketchat['driver']. ISocketProbe
names the four members the app calls, so the test double and the driver
harness derive from the facade instead of restating its shape.
* fix: read the subscribed host once when starting the rooms subscription
The hasClient guard and the later sdk.host read were two questions to a
mutable client: a disconnect between them left subServer null, matching
every later message whose host was also missing. subServer now starts
null and stop() clears it.
* refactor: name the driver contract for what it is and check it against the sdk
The facade's driver getter asserted through unknown to a hand-written
interface, so nothing verified that interface against the sdk's own
Driver. Assigning it directly makes tsc check the two, and the doubles
in the sdk harness still satisfy it structurally where Driver's private
socket would not.
* fix: drop rooms frames that arrive with no subscribed host
The host comparison passed when both sides were null, which is the state
between stop() clearing subServer and the stream listener being removed.
* refactor: annotate the abort exits like the disconnect beside them
* test: drop the unread client predicate from the rooms host-guard double
* refactor: read the subscribed host the same way in both rooms guards
* refactor: name the sdk predicate for the initialization it reports
* test: build the inline sdk doubles from the shared mock
The four inline jest.mock('../sdk') literals invented their own shape, so a
facade rename left them silently stale. They now come from makeSdkMock, whose
extra members are typed against the real facade, and presence flips through
setClient instead of a hand-rolled isInitialized getter.
* refactor: gate rooms frames on the subscribed server itself
The guard tested the live host before comparing it, which read as two
conditions when only the comparison decides. Both guards now read the host the
same way through subscribedHost().
* docs: say what triggerAction needs and stop naming a gone accessor
* refactor: read the subscribed host directly and restore the no-socket doc
Also isolates the stopped-subscription test to the subServer clear it covers.
* refactor: name the subscribed host and the mock driver for what they are
* refactor: inline the sdk mock's member constraint
* test: cover messages received while the device is offline (#7596)
* test: cover messages received while the device is offline
Adds a Maestro flow that drops the connection with airplane mode, posts messages over REST from the host while the device is offline, and asserts the backlog is delivered in order on reconnect.
* test: drop the maestro readme section
* test: settle before asserting the offline backlog is undelivered
* test: point the offline flow at the reconnect backfill code
* test: select the offline flow on subscribeRooms changes
* test: keep the sleep helper name
* test: include the offline flow shard in the rooms saga fan-out scenario
* chore: drop comments that restate or narrate code
* refactor: share the logged-in server lookup between the init and login sagas
* chore: drop the outcome enumeration from the recovery docblock
* refactor: type the logged-in server lookup with TServerModel
* fix: use the room _id when navigating to a newly created direct message
* chore: bump @rocket.chat/sdk to latest mobile HEAD
* fix: cold start drops a restored server when reading a pending notification fails (#7600)
* fix: keep the restored server when post-restore boot work throws
The restore saga wrapped its whole body in one try/catch that dispatched
appStart(ROOT_OUTSIDE), so an AsyncStorage failure or a malformed stored
push notification logged the user out of a workspace that had already
restored. Scope the recovery to server resolution and guard the push
notification handoff separately.
* refactor: split the restore saga into its boot steps
* refactor: centralise the server lookups behind the Server service (#7604)
* fix: restore a logged-in workspace when the current server was cleared
logout() clears CURRENT_SERVER and it is only re-set inside handleSelectServer.
A cold start in that window read an empty current server and dispatched
ROOT_OUTSIDE while another workspace was still fully logged in. Dropping
the early return lets the empty server fall through to the
findLoggedInServer() fallback, since hasStoredLoginToken('') is false.
* refactor: centralise the server lookups behind the Server service
Move the servers-table query into getAllServers so loggedInServer no
longer reaches into the database module, and make serverToRestore a
plain async function that authenticates whichever workspace it restores.
* fix: distinguish 2FA retry from cancel when saving the profile
handleTwoFactorChallenge returned a single boolean for three different outcomes, so a
cancelled challenge was indistinguishable from an issued retry, and a challenge that
failed for any other reason fell through to reporting the outer totp-invalid error
instead of the real one. It now returns a discriminated outcome and the caller owns
the saving-state reset.
* test: pin the normalized 2FA retry credentials for ldap and crowd (#7605)
`toPasswordLogin` flattens ldap/crowd credentials to `{ user, password }`
on every 2FA retry, dropping the `>= 3.9.0` server-version gate that used
to pass the raw params through on older servers. That gate is unreachable:
the built-in supported-versions floor is 6.3.x, and `selectServer`
disconnects any server whose status is expired, so a pre-3.9.0 server can
never reach the login flow.
Removing it was correct; these tests pin the surviving behaviour.
* Revert "fix: distinguish 2FA retry from cancel when saving the profile"
This reverts commit 56d3bb7.
* fix: stale 2FA code survives a cancelled prompt in ChangePasswordView (#7606)
* fix: keep the 2FA state reset when the two-factor prompt fails
The named isTwoFactorCancelled guard returned early, skipping the currentPassword/twoFactorCode reset the base reached through its bare catch, so a stale code survived into the next submit. A non-cancel failure also fell through and reported the outer totp-invalid error instead of the real one.
* refactor: extract the two-factor reset in ChangePasswordView
Also point the test's twoFactor mock at the module it replaces instead of relying on a re-export.
* fix: distinguish 2FA retry from cancel when saving the profile (#7607)
* fix: distinguish 2FA retry from cancel when saving the profile
handleTwoFactorChallenge returned a single boolean for three different outcomes, so a
cancelled challenge was indistinguishable from an issued retry, and a challenge that
failed for any other reason fell through to reporting the outer totp-invalid error
instead of the real one. It now returns a discriminated outcome and the caller owns
the saving-state reset.
* refactor: collapse the unchallenged 2FA outcome into the failed one
* refactor: import the 2FA cancellation guard from its leaf module (#7609)
* refactor: import the 2FA cancellation guard from its leaf module
* refactor: drop the 2FA cancellation re-export from the twoFactor barrel
* test: drop the dead requireActual spread from the twoFactor mock
* refactor: move the 2FA service into its own folder and TWO_FACTOR into constants
* refactor: keep localized upload-auth copy out of Error.message
* test: mock twoFactor from its module path
* fix: load history for rooms whose sync cursor was never seeded
`lastOpen` is a client-only cursor written only by `updateLastOpen`, which
no-ops when a fetch returned no messages. A room opened while empty therefore
kept a null cursor, and the sync gate skips the request without one, so the
reconnect catch-up could never seed it: every message that arrived while the
socket was open-but-dead stayed lost until the room was re-entered.
Fall back to a history load, which fetches the same gap and seeds the cursor.
* chore: bump @rocket.chat/sdk to latest mobile HEAD
* chore: point sniffler global at loggedInServer
* chore: bump @rocket.chat/sdk to SDK #421 head (#7618)
* chore: bump @rocket.chat/sdk to Rocket.Chat.js.SDK#421
* chore: point @rocket.chat/sdk at mobile HEAD
* chore: bump @rocket.chat/sdk to SDK #429 head
* chore: drop dead SDK exports and name what the socket and login helpers do (#7623)
* chore: drop dead exports and tests that assert nothing
Round 3 reviewed two angles the earlier rounds missed — the quality of the
tests this branch adds, and code left vestigial by the SDK bump.
Dead code:
- ILoginCredentials re-exported ten SDK credential types; six have no
consumer anywhere in app/.
- Four sdkIntegration test-util types were exported but referenced only
inside their own file.
- socketHealth: drop the "exported for unit tests" note and the usage
examples that restate both call sites. The concurrency and error-propagation
rationale stays, being the part the code cannot say.
Tests:
- twoFactorCancellation: 'surfaces a generic login error when the login path
reports a cancellation' passed `(cancelled as any).error`, which is
undefined on TwoFactorCancelledError — it asserted the default branch of
handleLoginErrors and would pass with the cancellation class deleted.
- restApi: 'returns signals and success from the API response' asserted the
shape of its own mock, already covered by the assertion above it.
- sdk.test: a jest.mock of constants/twoFactor returning the real module's
value verbatim.
Kept after checking: the eslint-disable on the removePushToken type import.
`oxlint --report-unused-disable-directives` calls it unused, but plain oxlint
fails without it, so the reporter is wrong here — the directive is live.
Also kept ISocketDriver rather than Pick<IDriver, ...>: the narrowing is what
keeps the test doubles small.
* refactor: inline the degenerate socket health classifier
Round 5 settles the question round 1 deferred. The two reviewers disagreed:
one wanted classifySocketHealth deleted as a one-line boolean, the other
wanted its ping-age fast path restored, claiming its removal added up to 2s
of probe latency before every reopen.
Commit 574125b answers it. The ping-age branch was removed as
UNREACHABLE, not as an optimisation: Socket.connected is
`transportOpen && alive()` and alive() is `now - lastPing <= ping * 2`, the
same multiplier the branch used. A stale-ping socket therefore already
reports `connected === false` and takes the reopen path with no round trip,
so no latency was added and there is nothing to restore.
That leaves a function, an exported two-member union and two tests to express
`!driver.connected`. Inline it into shareRecovery and drop the type. The two
deleted tests asserted only the mapping the one line states; recoverSocket's
own tests still pin both outcomes against a real socket.
* refactor: name the init saga helpers and the test flush for what they do
Round 6 reviewed hooks discipline and naming. Only the naming findings were
safe cleanups; the rest were either wrong or belong to code review.
- init: `findServerToRestore` also called localAuthenticate, so a `find*` name
promised a pure lookup while it could raise a biometric prompt and block —
every other `find*`/`get*` here is pure. It becomes `restoreServer`, and the
generator wrapping it becomes `getServerToRestore`, matching the verb naming
of every other saga in the file.
- testUtils: `flush(turns)` also advanced jest timers, which the name hid, and
sat next to `flushSagaMicrotasks` with no way to tell them apart. It becomes
`flushMicrotasksAndTimers`.
Rejected, each checked against the code:
- Assert upload auth headers in the constructor: reverts abcf41d. The
constructor throw happened before the caller could store the instance in its
upload queue, so sendFileMessage read the missing entry as a cancellation and
swallowed the error. Send-time validation is the fix, not the smell.
- Drop the TwoFactor `pendingCancel` ref: load-bearing. The listener registers
with `[]` deps, so its closure never sees the current `data`.
- Make sdk.subscribe's `eventName` required: getUsersPresence.ts:32 calls
`sdk.subscribe('activeUsers')` with no event name.
- Reuse getSenderName for the members display name: it reads redux directly
and has no fallback chain.
Left for code review, being a defect rather than a cleanup: useAvatarETag
wraps its whole effect body in `if (!avatarETag)`, so once an ETag is set an
identity change never resubscribes and the hook keeps serving the previous
user's ETag.
* refactor: name the loginTOTP password-retry flag at its call sites
Round 7.
- loginTOTP's second parameter was a bare boolean: `loginTOTP(params, true)`
and `loginTOTP(params, false)` said nothing at the call site about what was
being switched. It now takes `{ retryWithPassword }`, which is what the flag
actually selects — whether a totp retry re-derives password credentials via
toPasswordLogin. The OAuth/SSO caller passed `false`, so it simply drops the
argument.
- socketHealth.integration: drop 'exposes the ping interval the health
classification depends on'. It asserted that the harness driver carries the
PING_INTERVAL the test itself configured, and the classification it named
stopped existing in 889cb21d36.
Rejected:
- Merging init.fallbackServer.test into init.test: not sloppiness but a
constraint. init.test mocks UserPreferences down to `getString`, while the
fallback suite drives the real implementation through setString/removeItem.
jest.mock is file-scoped, so the two storage strategies cannot share a file.
- Deduplicating 'reopens a known-dead socket without a round trip' across the
unit and integration suites: they prove different things. The unit test
closes the transport directly; the integration test backdates lastPing and
relies on `connected` folding the ping-age test in — which is precisely the
invariant that made the classifier removable, so it is now load-bearing.
* chore: bump @rocket.chat/sdk to mobile HEAD (2.0.0-mobile)
---------
Co-authored-by: Diego Mello <diego.mello@rocket.chat>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Version 9.0.0 of babel-eslint was just published.
The version 9.0.0 is not covered by your current version range.
If you don’t accept this pull request, your project will work just like it did before. However, you might be missing out on a bunch of new features, fixes and/or performance improvements from the dependency update.
It might be worth looking into these changes and trying to get this project onto the latest version of babel-eslint.
If you have a solid test suite and good coverage, a passing build is a strong indicator that you can take advantage of these changes directly by merging the proposed change into your project. If the build fails or you don’t have such unconditional trust in your tests, this branch is a great starting point for you to work on the update.
Commits
The new version differs by 15 commits ahead by 15, behind by 2.
6aa8b6f9.0.0c7ee9aeBump to babel@7.0.0 🎉 (#676)3ece549Docs: Make the default parserOptions more explicit (#673)0b36951Add logical assignment plugin (#674)5856ff5Bump some devDeps45938d9build(deps): upgrade @babel/* to 7.0.0-rc.2 (#668)bc978759.0.0-beta.374c5d62update lock6a45632chore - fixing eslint-scope to a safe version; resolves #656. (#657)e0119e09.0.0-beta.2198964bMerge pull request #645 from rubennorte/support-new-flow-syntax-in-scope-analysis9b06e1fAdded failing test for variables used in type parameters8948d83Upgrade Babel to v7.0.0-beta.52 (#650)4882b299.0.0-beta.115e8d6fBreaking: Upgraded Babel to 7.0.0-beta.51 (#642)See the full diff
FAQ and help
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper bot 🌴