Skip to content

feat: alerts store — track APEX notifications with unseen badge - #28

Merged
jackinabox86 merged 3 commits into
mainfrom
claude/cool-lovelace-jOfdQ
May 22, 2026
Merged

feat: alerts store — track APEX notifications with unseen badge#28
jackinabox86 merged 3 commits into
mainfrom
claude/cool-lovelace-jOfdQ

Conversation

@jackinabox86

Copy link
Copy Markdown
Owner

Summary

Adds full support for APEX's notification/alerts system (ALERTS_* WebSocket messages), mirroring the pattern used by refined-prun's alertsStore. Unseen alerts are surfaced in the UI via a gold badge on the SHOW APEX button, and a window.apxm debug handle makes store inspection easy from the browser console.


What changed

New: stores/entities/alerts.ts

A Zustand entity store keyed by alert.id, created with createEntityStore — the same factory used by contracts, ships, flights, etc. No persistence (alerts are session-lived; the server re-sends them on reconnect).

export const useAlertsStore = createEntityStore<PrunApi.Alert>('alerts', (a) => a.id);

New types in types/prun-api.ts

  • PrunApi.Alert — matches the wire format exactly: id, type, contextId, naturalId, time (DateTime), data (AlertData[]), seen, read
  • PrunApi.AlertData{ key: string; value: string | AlertDataEntity }. The value field is polymorphic: simple keys like commodity carry a plain string, entity keys like exchange carry an object with id / name / code / _type. This was confirmed against a live WS capture.
  • PrunApi.AlertType — union of ~20 known string literals (PRODUCTION_ORDER_FINISHED, SHIP_FLIGHT_ENDED, COMEX_ORDER_FILLED, etc.) plus string as a fallback for types not yet seen in the wild.

Three message handlers in stores/message-handlers.ts

Message Action
ALERTS_ALERTS setMany + setFetched('websocket') — bulk dump on login
ALERTS_ALERT setOne — new or updated single alert
ALERTS_ALERTS_DELETED removeOne loop over alertIds

All handlers go through the existing extractPayload helper and follow the same guard/warn pattern as every other handler in the file.

stores/entities/index.ts

  • useAlertsStore and AlertsStore exported
  • useAlertsStore.getState().clear() added to clearAllEntityStores() (called on reconnect)
  • useAlertsStore added to the allStores batch array so it participates in the two-layer shadow-batching system that prevents React error #185 during login bursts

UI: unseen badge on SHOW APEX (components/layout/Header.tsx)

When any stored alert has seen === false, a gold (N) appears inline to the right of the SHOW APEX text. The selector iterates entities.values() directly (no intermediate array) and returns a plain number, so the header only re-renders when the count actually changes.

{unseenCount > 0 && (
  <span className="text-prun-yellow">({unseenCount})</span>
)}

Console debug handle (entrypoints/content.tsx)

After the React overlay mounts, window.apxm is set with a reference to the store. Useful for verifying alerts are being received without needing the diagnostic overlay:

window.apxm.alerts.getState().fetched          // true once ALERTS_ALERTS fires
window.apxm.alerts.getState().getAll()          // all alerts
window.apxm.alerts.getState().entities.size     // quick count
window.apxm.alerts.getState().getAll().filter(a => !a.seen)  // unseen only

Batch pipeline note

Alert store mutations go through beginEntityBatch / endEntityBatch like every other entity store. No special handling needed — createEntityStore's shadow state mechanism takes care of it automatically once the store is added to the allStores array in index.ts.


Generated by Claude Code

claude added 3 commits May 22, 2026 19:08
Tracks ALERTS_ALERTS (bulk), ALERTS_ALERT (single), and ALERTS_ALERTS_DELETED
messages into a Zustand entity store, mirroring the refined-prun alertsStore pattern.

https://claude.ai/code/session_013u5JnLg2kZSaDHnHDBzmKJ
Wire payload shows exchange values arrive as objects with id/name/code/_type.

https://claude.ai/code/session_013u5JnLg2kZSaDHnHDBzmKJ
- Header: show (N) in prun-yellow next to SHOW APEX when unseen alerts exist
- content.tsx: expose window.apxm.alerts after UI mounts for console inspection

https://claude.ai/code/session_013u5JnLg2kZSaDHnHDBzmKJ
@jackinabox86
jackinabox86 merged commit 33bb9d8 into main May 22, 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.

2 participants