Skip to content

fix(market-data): hot-reload provider + credentials when config changes#136

Merged
luokerenx4 merged 1 commit intomasterfrom
dev
Apr 21, 2026
Merged

fix(market-data): hot-reload provider + credentials when config changes#136
luokerenx4 merged 1 commit intomasterfrom
dev

Conversation

@luokerenx4
Copy link
Copy Markdown
Contributor

Summary

Changing `marketData.providers` via the UI had no effect — every `/api/market-data-v1/*` request kept resolving to the provider that was live at server boot, because the resolver closure and the `defaultCredentials` value were both snapshotted at `mountOpenTypeBB` time, and `ctx.config` itself is never reassigned when the config-write route persists edits to disk (only the Telegram / MCP-Ask reconnect path was wired to the PUT handler, and it doesn't touch opentypebb).

Three mechanical changes close the loop:

  • opentypebb `mountToHono`'s `defaultCredentials` widens to `value | null | (() => value | null)` and re-evaluates the getter on each request, mirroring the `resolveProvider` callback that was already lazy.
  • Alice's mount helper (`src/server/opentypebb.ts`) accepts static values or getters for both `defaultProviders` and `defaultCredentials`; the resolver reads via getter per request.
  • web-plugin passes closures that read `ctx.config.marketData.{providers,providerKeys}` per invocation.
  • config PUT route (`routes/config.ts`): after `writeConfigSection`, reload the full config and `Object.assign` onto `ctx.config` so in-memory state stays in sync with disk. Preserves `ctx.config`'s object identity.

TODO.md gets an Architecture entry flagging this as a band-aid — three different config-sync strategies now coexist (connector reconnect, opentypebb lazy getter + Object.assign, sub-reference capture that just goes stale), and the right fix is a unified pub/sub config bus plus a file watcher for out-of-band edits. Worth one focused pass next time something goes stale.

Test plan

  • `npx tsc --noEmit` clean
  • `pnpm test` — 1088 tests / 56 files pass
  • Live flip without restart: `PUT /api/config/marketData` with `providers.equity = 'fmp'` → next `/api/market-data-v1/equity/price/quote` returns `provider: fmp`; flip back to `yfinance` → returns `yfinance`. Both directions, zero restart.
  • Credentials path: adding an FMP API key via UI takes effect on the next request to an FMP-gated endpoint.

🤖 Generated with Claude Code

Changing marketData.providers via the UI had no effect — every
/api/market-data-v1/* request kept resolving to the provider that was
live at server boot. The resolver closure and the defaultCredentials
value were both snapshotted at mountOpenTypeBB time, and ctx.config
itself is never reassigned when the config-write route persists edits
to disk; only the Telegram / MCP-Ask reconnect path was wired to the
PUT handler, and it doesn't touch opentypebb.

Three mechanical changes close the loop:

- packages/opentypebb mountToHono's defaultCredentials widens to
  `value | null | (() => value | null)` and re-evaluates the getter on
  each request, mirroring the resolveProvider callback that was
  already lazy.
- src/server/opentypebb.ts MountOpenTypeBBOptions accepts either static
  values or getters for both defaultProviders and defaultCredentials;
  makeProviderResolver reads via getter per request.
- src/connectors/web/web-plugin.ts passes closures that read
  ctx.config.marketData.{providers,providerKeys} on each invocation.
- src/connectors/web/routes/config.ts: after writeConfigSection, reload
  the full config and Object.assign onto ctx.config so in-memory state
  stays in sync with disk. Preserves ctx.config's object identity.

Verified live: flipping equity provider via PUT /api/config/marketData
flips the response's `provider` field on the very next request to the
market-data endpoints, both directions, no restart.

TODO.md gets an Architecture entry flagging that this is a band-aid —
three different config-sync strategies now coexist, and the right fix
is a unified pub/sub config bus plus a file watcher for out-of-band
edits. Worth doing one focused pass next time something goes stale.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@luokerenx4 luokerenx4 merged commit a669fc8 into master Apr 21, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant