このコミットが含まれているのは:
2026-10-19 00:03:55 +09:00
コミット a86129006d
37個のファイルの変更、800行の追加、224行の削除
+22 -1
ファイルの表示
@@ -26,7 +26,10 @@ const withUserCode = (opt?: Opt): AxiosRequestConfig => {
&& { baseURL: currentRenderContext ()!.apiBaseURL, timeout: 10_000 }),
...(locale != null && { params: { locale, ...config.params } }),
headers: { 'X-Transfer-Code': typeof window === 'undefined'
? '' : localStorage.getItem ('user_code') ?? '',
? currentRenderContext ()?.transferCode ?? ''
: localStorage.getItem ('user_code') ?? '',
...(currentRenderContext ()?.forwardedFor != null && {
'X-Forwarded-For': currentRenderContext ()!.forwardedFor }),
...(config.headers ?? { }) } }
}
@@ -37,6 +40,24 @@ const apiP = async <T> (
body?: unknown,
opt?: Opt): Promise<T> => {
const res = await client[method] (path, body ?? { }, withUserCode (opt))
if (typeof window !== 'undefined' && method === 'post'
&& ['/users', '/users/verify', '/users/code/renew'].includes (path))
{
const code = res.data?.code ?? (res.data?.valid ? (body as { code?: string })?.code : null)
if (typeof code === 'string')
{
try
{
await fetch ('/_ssr/session', {
method: 'POST', credentials: 'same-origin',
headers: { 'X-Transfer-Code': code } })
}
catch
{
// Existing CSR authentication remains usable if the SSR endpoint is unavailable.
}
}
}
if (opt?.responseType === 'blob')
return res.data as T
return toCamel (res.data as Record<string, unknown>, { deep: true }) as T
+12
ファイルの表示
@@ -123,6 +123,8 @@ export const materialsKeys = {
export const wikiKeys = {
root: ['wiki'] as const,
diff: (id: string, p: { from: string | null; to: string | null }, locale: LocaleCode) =>
['wiki', locale, 'diff', id, p] as const,
autolinkCandidates: (language: string, locale: LocaleCode) =>
['wiki', 'autolink', locale, language] as const,
index: (
@@ -147,3 +149,13 @@ export const helpKeys = {
diff: (identifier: string, language: string, from: string, to: string) =>
['help', 'diff', identifier, language, from, to] as const,
changes: (language: string) => ['help', 'changes', language] as const }
export const sessionKeys = {
current: ['session', 'current'] as const,
settings: (id: number) => ['session', id, 'settings'] as const,
themeSlots: (id: number) => ['session', id, 'themeSlots'] as const }
export const theatresKeys = {
show: (id: string, locale: LocaleCode) => ['theatres', locale, id] as const,
programmes: (id: string, locale: LocaleCode) =>
['theatres', locale, id, 'programmes'] as const }
+4 -1
ファイルの表示
@@ -1,7 +1,10 @@
export type RenderContext = {
pathname: string
origin: string
apiBaseURL?: string }
apiBaseURL?: string
transferCode?: string
forwardedFor?: string
status?: number }
// The server build replaces this module with the AsyncLocalStorage implementation.
+4 -1
ファイルの表示
@@ -10,8 +10,11 @@ export type PagePreparation = {
searchParams: URLSearchParams }
export type PageRouteHandle = {
ssr?: (request: PagePreparation) => Promise<number>
prepare?: (request: PagePreparation) => Promise<number>
locale?: LocaleCode
robots?: 'noindex'
authentication?: 'user'
redirectTo?: string
notFound?: boolean }
export type PageRoute = { handle?: PageRouteHandle } & (
+2 -1
ファイルの表示
@@ -791,7 +791,8 @@ export const seedClientThemeMode = (theme: UserSettings['theme']): void => {
const prefersDarkTheme = (): boolean =>
window.matchMedia ('(prefers-color-scheme: dark)').matches
typeof window !== 'undefined'
&& window.matchMedia ('(prefers-color-scheme: dark)').matches
export const resolveThemeMode = (
+9
ファイルの表示
@@ -0,0 +1,9 @@
import { useSyncExternalStore } from 'react'
const subscribe = () => () => { }
const clientSnapshot = () => true
const serverSnapshot = () => false
export const useHydrated = (): boolean =>
useSyncExternalStore (subscribe, clientSnapshot, serverSnapshot)
+5 -1
ファイルの表示
@@ -99,12 +99,16 @@ export const KeyboardShortcutsProvider = ({ children }: PropsWithChildren) => {
const navigate = useLocaleNavigate ()
const [keyboardSettings, setKeyboardSettingsState] =
useState<ClientKeyboardSettings> (() => getClientKeyboardSettings ())
useState<ClientKeyboardSettings> ({ enabled: true, bindings: { } })
const [registeredHandlers, setRegisteredHandlers] =
useState<Record<number, ShortcutHandlers>> ({ })
const [shortcutHelpOpen, setShortcutHelpOpen] = useState (false)
const registrationIdRef = useRef (0)
useEffect (() => {
setKeyboardSettingsState (getClientKeyboardSettings ())
}, [])
const activeScope = useMemo<ShortcutScope> (
() => resolveShortcutScope (location.pathname),
[location.pathname],