/** * Cache-key conventions for the local-first store (`@/shared/storage`). * * One key per (scope, payload): the key is the contract between a `useAsync` * consumer, a hover `prefetch` and any mutation that invalidates — building * them here keeps the three from drifting apart. Pure string arithmetic, no * business logic, which is why this lives in shared. * * Scopes nest by prefix so `invalidateCache('space:foo:')` drops everything * belonging to one space. Always invalidate with the trailing separator. * * The member list intentionally has three keys: three fetchers post-process * the same endpoint into three different payload shapes (admin rows with * limit 200, chat's flattened picker rows, the issue board's page object), * and a shared key would serve one consumer another's shape. */ /* ---------------------------------------------------------- global identity */ export const meKey = () => 'me' export const spacesKey = () => 'spaces' export const dmsKey = () => 'dms' /* ------------------------------------------------------- space-scoped lists */ export const spaceRoomsKey = (space: string) => `space:${space}:rooms` export const spaceDirKey = (space: string) => `space:${space}:dir` export const spaceReposKey = (space: string) => `space:${space}:repos` /** * The full name-sorted repo list behind the repo pickers (link a PR, …). * * Deliberately separate from `spaceReposKey`: the sidebar fetches 50 rows in * default order, this one up to 100 in name order, and `useAsync` caches by key * alone — one key for both would let whichever loaded first decide the other's * ordering and truncation. */ export const spaceReposPickKey = (space: string) => `space:${space}:repos:pick` export const spaceBoardsKey = (space: string) => `space:${space}:boards` export const spaceEmojisKey = (space: string) => `space:${space}:emojis` /** features/space-management rows (limit 200). */ export const spaceAdminMembersKey = (space: string) => `space:${space}:admin:members` /** entities/chat flattened picker rows (limit 100). */ export const spaceMembersFlatKey = (space: string) => `space:${space}:members:flat` /** entities/issue page object (limit 100). */ export const spaceMembersPageKey = (space: string) => `space:${space}:members:page` /** * Space settings/admin sections: `invites`, `groups`, `bans`, `join-rules`, * `membership`, `images`, `settings`, `overwrites:{nodeId}`, … */ export const spaceAdminKey = (space: string, part: string) => `space:${space}:admin:${part}` /** * One uploaded space image (`banner`, `icon`, …) as a single `SpaceImage` row. * * Distinct from `spaceAdminKey(space, 'images')`, which caches the *record of * all kinds* the settings section renders: sharing a key would serve one * consumer the other's shape. The sidebar reads this key so a community banner * is on screen from the first frame instead of arriving after a refetch. */ export const spaceImageKey = (space: string, kind: string) => `space:${space}:image:${kind}` /** Whole-space invalidation prefix (note the trailing separator). */ export const spacePrefix = (space: string) => `space:${space}:` /* --------------------------------------------------------------------- chat */ /** Room side data: `room`, `members`, `pins`, `threads`. */ export const roomKey = (roomId: string, part: string) => `room:${roomId}:${part}` /** Transcript seed page of one scope (`threadId === null` is the main stream). */ export const chatSeedKey = (roomId: string, threadId: string | null) => `chat:${roomId}:${threadId ?? 'main'}:seed` /* ------------------------------------------------------------------- issues */ /** Board payloads: `board`, `labels`, `milestones`, `issues:{queryKey}`. */ export const boardKey = (space: string, board: string, part: string) => `board:${space}/${board}:${part}` /** Issue payloads: `detail`, `labels`, `comments`, `events`. */ export const issueKey = (space: string, board: string, issueId: string, part: string) => `issue:${space}/${board}/${issueId}:${part}` /* -------------------------------------------------------------------- repos */ /** * Repo payloads: `detail`, `tags`, `branches:{limit}`, `tree:{rev}:{path}`, * `readme:{rev}:{path}`, `commits:…`, `diff:…`, `remotes`, `topics`, * `insights:…`, `lfs-locks:…`. */ export const repoKey = (space: string, repo: string, part: string) => `repo:${space}/${repo}:${part}` /* ------------------------------------------------------------ notifications */ /** `list:{filter}`, `unread`. */ export const notifyKey = (part: string) => `notify:${part}` /* ----------------------------------------------------------- user settings */ /** `preferences`, `emails`, `sessions`, `totp`, `access-keys`, `ssh-keys`, `suspensions`. */ export const settingsKey = (part: string) => `settings:${part}`