Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
63 lines
2.5 KiB
TypeScript
63 lines
2.5 KiB
TypeScript
// IMPORTANT — import order is load-bearing:
|
|
// 1. temporal-polyfill/global must register Temporal on globalThis BEFORE any
|
|
// Schedule-X code runs (Schedule-X v4 uses Temporal objects at module init).
|
|
// 2. Schedule-X theme-default CSS must be imported BEFORE tokens.css so that
|
|
// the project's --sx-color-* overrides in tokens.css win the cascade.
|
|
// 3. styles/index.css imports tokens.css which carries the --sx-color-* overrides.
|
|
import 'temporal-polyfill/global';
|
|
import '@schedule-x/theme-default/dist/index.css';
|
|
import './styles/index.css';
|
|
|
|
import React from 'react';
|
|
import ReactDOM from 'react-dom/client';
|
|
import { QueryClient, QueryClientProvider, QueryCache, MutationCache } from '@tanstack/react-query';
|
|
import App from './App.js';
|
|
import { ErrorBoundary } from './components/ErrorBoundary.js';
|
|
import { SessionExpiredError } from './api/client.js';
|
|
import { useCalendarStore } from './store/calendarStore.js';
|
|
|
|
/**
|
|
* Global session-expiry error handler (D-11, Plan 06-05).
|
|
*
|
|
* When any query or mutation throws a SessionExpiredError, arm the interstitial
|
|
* via the Zustand store's imperative getter — safe to call outside React since
|
|
* Zustand's create() returns a store with a .getState() API.
|
|
*
|
|
* QueryCache and MutationCache onError callbacks are the correct v5 pattern for
|
|
* global error handling (NOT defaultOptions.onError, which was removed in v5).
|
|
* Confirmed via Context7 /tanstack/query docs for v5.101.0.
|
|
*/
|
|
function onGlobalError(error: unknown): void {
|
|
// WR-05: instanceof can fail if client.ts is ever loaded through two module graphs
|
|
// (Vite SSR, duplicated chunk, or the tests' repeated `await import('./client.js')`),
|
|
// leaving the session-expiry interstitial unarmed. SessionExpiredError carries a fixed
|
|
// `name` for identity stability, so also check that defensively.
|
|
if (
|
|
error instanceof SessionExpiredError ||
|
|
(error as { name?: string } | null)?.name === 'SessionExpiredError'
|
|
) {
|
|
useCalendarStore.getState().setSessionExpired(true);
|
|
}
|
|
}
|
|
|
|
const queryClient = new QueryClient({
|
|
queryCache: new QueryCache({ onError: onGlobalError }),
|
|
mutationCache: new MutationCache({ onError: onGlobalError }),
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: 1,
|
|
staleTime: 30_000,
|
|
},
|
|
},
|
|
});
|
|
|
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
<React.StrictMode>
|
|
<QueryClientProvider client={queryClient}>
|
|
<ErrorBoundary>
|
|
<App />
|
|
</ErrorBoundary>
|
|
</QueryClientProvider>
|
|
</React.StrictMode>,
|
|
);
|