mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
* refactor(session): migrate SessionProvider to React Query useSessionQuery
Replace the hand-rolled useState/useEffect/loadSession session loading in
SessionProvider with a useSessionQuery() React Query hook. The SessionContext
shape is unchanged ({ data, isPending, error, refetch }) so no consumer changes.
The 'upgraded' path still forces a fresh DB read via
client.getSession({ query: { disableCookieCache: true } }) (refetch() cannot
pass disableCookieCache) and writes the result via queryClient.setQueryData,
then invalidates ['organizations']/['subscription'] as before.
* refactor(workflows): collapse duplicate workflow-state cache
The registry store fetched the GET /api/workflows/[id] envelope inline via
requestJson while useWorkflowState cached the same endpoint's mapped state
under workflowKeys.state(id) — two requests, two cache shapes, never
reconciled.
Collapse to one request + one cache entry keyed by workflowKeys.state(id):
- Add hooks/queries/utils/fetch-workflow-envelope.ts: a standalone
fetchWorkflowEnvelope(id, signal) returning the full GetWorkflowResponseData.
Standalone (not in workflows.ts) to avoid a store -> query-hook import cycle.
- useWorkflowState/useWorkflowStates now query the envelope and derive the
mapped WorkflowState via select (mapWorkflowState), so consumers see the
identical mapped shape from the shared entry.
- The store's loadWorkflowState reads via getQueryClient().fetchQuery({
staleTime: 0 }) instead of raw requestJson — always-fresh (preserving the
prior always-fetch boot/refresh semantics, incl. the socket
handle-resource-event refresh path that has no separate state
invalidation), in-flight deduped, writing into the same cache entry the
hooks read.
Request-id staleness guard, deployment-cache priming, cross-store projection,
and the active-workflow-changed event are all preserved unchanged.
* fix(workspace): add granular error boundaries to logs, knowledge, and files panels
Scope a crash in one workspace panel to that panel instead of the whole
workspace shell. Each boundary reuses the shared ErrorState component and
mirrors the existing tables/settings error.tsx convention.
* refactor(unsubscribe): migrate page to React Query
Replace the hand-rolled useState+useEffect+requestJson server-state in the
unsubscribe page with React Query hooks. Add useUnsubscribe (validation/load
query, keyed by email+token, auto-runs on mount via enabled) and
useUnsubscribeMutation (unsubscribe action, reconciles cached preferences on
success) in hooks/queries/unsubscribe.ts with a hierarchical key factory.
Export UnsubscribeData/UnsubscribeActionResponse/UnsubscribeType type aliases
from the existing user contract; loading/error/success now derive from the
query and mutation objects with no local server-state mirror.
* test(frontend-arch): cover session race fix, workflow-state cache collapse, unsubscribe, error boundary
Add targeted tests for the four frontend-architecture refactors:
- session-provider: upgrade-path ordering — fresh disableCookieCache read wins
over a late-resolving stale mount query (proves the cancelQueries guard)
- fetch-workflow-envelope + registry store: single shared state(id) cache entry,
always-refetch (staleTime 0), request-id staleness guard
- unsubscribe: query enable-gating + mutation cache reconcile
- logs error boundary: renders ErrorState + reset wiring (also first ErrorState coverage)
* fix(session): harden upgrade path + address review feedback
- Reconcile plan surfaces after upgrade even when the fresh disableCookieCache
read fails: invalidate ['organizations']/['subscription'] regardless of the
bypass-read outcome (they read server truth, not the cookie cache). The valid
cookie-cached session is still served, so a transient failure no longer signs
the user out or leaves the just-upgraded plan looking stale. Org-activate
fallback stays gated on having a session.
- Use a bare return in the cancelled branch of refreshAfterUpgrade (the caller
discards the value) for clearer intent; caller coerces with ?? null.
- Make the upgrade tests deterministic: the mount mock honors the abort signal
like the real fetch-backed client, and assertions read the query cache (the
state cancelQueries/setQueryData/invalidation actually govern) instead of the
async-rendered context value.
* refactor(session): break provider<->hook type cycle, fail-fast session query
Address review feedback:
- Move the AppSession type to lib/auth/session-response.ts (the module that
produces it) so useSessionQuery and SessionProvider both import it from there,
eliminating the provider <-> query-hook import cycle.
- Add retry: false to useSessionQuery, restoring the prior fail-fast contract
(the global QueryClient default is retry: 1; an auth failure should surface
immediately rather than retry a request that won't succeed).
- Return null (not the fetched value) from refreshAfterUpgrade's cancelled
branch to make the cancellation contract explicit.