Fix TopstepX login loop on bundled builds: signalr's dynamic require

@microsoft/signalr does an unconditional require('ws')/require('eventsource')
when constructing a connection; bundled (turbopack) builds throw 'dynamic
usage of require is not supported', which the login chain mislabelled as a
login failure and retried every 60s. Externalize the package and never let
hub setup fail the login — REST polling covers everything the hub does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-09-13 13:28:09 -05:00
co-authored by Claude Fable 5
parent 153b1273c3
commit 4edb771701
2 changed files with 18 additions and 2 deletions
+14 -1
View File
@@ -172,7 +172,14 @@ export class TopstepXClient implements PlatformClient {
if (this.syncInterval) { clearInterval(this.syncInterval); this.syncInterval = null; }
this.syncComplete = false;
await this.startHub();
// Hub failure must never read as a login failure: REST polling
// carries every feature (slower), and subscribeAll retries the
// hub on each sync tick.
try {
await this.startHub();
} catch (err) {
console.error('[topstepx] hub setup failed — running on REST polling only', err instanceof Error ? err.message : err);
}
await this.requestSync();
this.syncInterval = setInterval(() => void this.requestSync(), 60_000);
@@ -240,6 +247,12 @@ export class TopstepXClient implements PlatformClient {
}
this.subscribedAccountIds.clear();
// signalr's Node path does an unconditional dynamic require('ws') /
// require('eventsource') when constructing the connection — bundled
// builds throw "dynamic usage of require is not supported" on it, so
// the package is listed in next.config serverExternalPackages and any
// residual failure here is caught by the caller (REST polling covers
// everything the hub does, just slower).
const hub = new signalR.HubConnectionBuilder()
.withUrl(USER_HUB, {
skipNegotiation: true,