this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Clear lint fallout from the SDK-hook migration

Nine errors survived the large-scale migration: unnecessary type
assertions in FileView, EditorView, and auth.ts (autofix cleared);
a mutable-array declaration in fileContext.ts's snapshotToFileItems
(switched to readonly — the sort operates on a copy anyway); and
two set-state-in-effect warnings that are load-bearing:

- FileView's two-phase directory resolution has to run in an effect.
The snapshot from useDirectory is both the input to and the
derivation source for targetDirectoryUri, and there's no useMemo
shape that expresses that dependency cycle. Inline-suppress with
a pointer to the explanation comment.
- EditorView's loaded→displayName sync is exactly the "external async
source" case the rule documents as allowed, but the linter can't
see through useDocumentContent's boundary. Same treatment.

+24 -13
+5
apps/web/src/components/cabinet/EditorView.tsx
··· 118 118 const { loaded, error } = useDocumentContent(fm, documentUri); 119 119 120 120 // Sync displayName with the loaded document's name in edit mode. 121 + // The load is async and external (IndexedDB / PDS round-trip), so 122 + // this is the "sync external data into React state" case the rule 123 + // explicitly allows; suppress since ESLint can't see through 124 + // useDocumentContent's boundary. 121 125 useEffect(() => { 126 + // eslint-disable-next-line react-hooks/set-state-in-effect -- external async source, see comment 122 127 if (loaded?.documentName) setDisplayName(loaded.documentName); 123 128 }, [loaded]); 124 129
+16 -10
apps/web/src/components/cabinet/FileView.tsx
··· 117 117 resolvedDirectoryUri, 118 118 } = useDirectory(keyringUri, targetDirectoryUri); 119 119 120 + // Derive the resolved directory URI from the snapshot + pathSegments. 121 + // This has to be an effect (not a useMemo) because the snapshot comes 122 + // from `useDirectory` AND is the input to the next render's 123 + // `useDirectory` call — we can't know the target URI until a root- 124 + // watch snapshot has arrived. targetDirectoryUri intentionally 125 + // omitted from the dep list — including it would oscillate when 126 + // resolve returns the current value. 120 127 useEffect(() => { 121 128 if (!snapshot) return; 122 129 const resolved = 123 130 pathSegments.length === 0 ? null : resolveDirectoryFromSplat(snapshot, pathSegments); 124 131 if (resolved !== targetDirectoryUri) { 132 + // eslint-disable-next-line react-hooks/set-state-in-effect -- two-phase directory resolution; see comment above 125 133 setTargetDirectoryUri(resolved); 126 134 } 127 - // targetDirectoryUri intentionally omitted — including it would cause an 128 - // oscillation when the resolve result equals the current state. 129 135 // eslint-disable-next-line react-hooks/exhaustive-deps 130 136 }, [snapshot, pathSegments.join("/")]); 131 137 ··· 199 205 if (context.kind === "workspace") { 200 206 const wsRkey = rkeyFromUri(context.keyringUri); 201 207 void navigate({ 202 - to: "/cabinet/workspace-editor/$rkey/$docRkey" as never, 203 - params: { rkey: wsRkey, docRkey: rkey } as never, 208 + to: "/cabinet/workspace-editor/$rkey/$docRkey", 209 + params: { rkey: wsRkey, docRkey: rkey }, 204 210 }); 205 211 } else { 206 - void navigate({ to: "/cabinet/editor/$rkey" as never, params: { rkey } as never }); 212 + void navigate({ to: "/cabinet/editor/$rkey", params: { rkey } }); 207 213 } 208 214 }, 209 215 [navigate, context], ··· 214 220 if (context.kind === "workspace") { 215 221 const wsRkey = rkeyFromUri(context.keyringUri); 216 222 void navigate({ 217 - to: "/cabinet/workspace-editor/$rkey/new" as never, 218 - params: { rkey: wsRkey } as never, 219 - search: search as never, 223 + to: "/cabinet/workspace-editor/$rkey/new", 224 + params: { rkey: wsRkey }, 225 + search: search, 220 226 }); 221 227 } else { 222 228 void navigate({ 223 - to: "/cabinet/editor/new" as never, 224 - search: search as never, 229 + to: "/cabinet/editor/new", 230 + search: search, 225 231 }); 226 232 } 227 233 }, [navigate, context, currentDirectoryUri]);
+1 -1
apps/web/src/lib/fileContext.ts
··· 36 36 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard 37 37 if (!dir) return []; 38 38 39 - const items: FileItem[] = dir.entries.map((entry) => { 39 + const items: readonly FileItem[] = dir.entries.map((entry) => { 40 40 if (entry.type === "directory") { 41 41 const info = snapshot.directories[entry.uri] as 42 42 | (typeof snapshot.directories)[string]
+2 -2
apps/web/src/stores/auth.ts
··· 229 229 230 230 export const useAuthStore = create<AuthStore>()( 231 231 immer((set) => ({ 232 - session: { status: "initializing" } as SessionState, 233 - identity: { status: "pending" } as IdentityState, 232 + session: { status: "initializing" }, 233 + identity: { status: "pending" }, 234 234 235 235 async boot() { 236 236 // Deduplicate concurrent calls (StrictMode, HMR, multiple route guards)