local-replica 0.0.0 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -2
- package/dist/createReplicaEngine-CdR-URHo.js +2018 -0
- package/dist/createReplicaEngine-CdR-URHo.js.map +1 -0
- package/dist/index-DsElitHD.d.ts +856 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +281 -0
- package/dist/index.js.map +1 -0
- package/dist/zustand/index.d.ts +353 -1
- package/dist/zustand/index.js +641 -0
- package/dist/zustand/index.js.map +1 -0
- package/package.json +10 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createReplicaEngine-CdR-URHo.js","names":[],"sources":["../src/core/resource/storageKey.ts","../src/core/resource/queryKeys.ts","../src/core/paging/operations.ts","../src/core/persistence/writeQueue.ts","../src/core/persistence/persistedRows.ts","../src/core/entity/propagation.ts","../src/core/state/reducer.ts","../src/core/engine/pagination.ts","../src/core/engine/tombstones.ts","../src/core/engine/removalGuards.ts","../src/core/engine/scopeClear.ts","../src/core/engine/createReplicaEngine.ts"],"sourcesContent":["/** Persisted row key: one row per entry key and query. */\nexport const replicaStorageKey = (key: string, query?: string) => (query ? `${key}?${query}` : key);\n\n/**\n * Whether `storageKey` is a persisted row of entry `key`, under any query.\n *\n * Entry keys are free-form, so a `?` prefix alone cannot tell `foo` + a query\n * from a plain entry `foo?bar`. A row only counts as a variant when it is\n * exactly `replicaStorageKey(key, query)` for a query this module could have\n * written: the rest after `key?` must be a canonical `stableQueryKey` (it\n * parses as JSON and serializes back to itself). Row keys and the index keep\n * their existing flat format, so rows already persisted on devices match the\n * same way.\n */\nexport const isReplicaStorageKeyOf = (storageKey: string, key: string): boolean => {\n if (storageKey === key) return true;\n if (!storageKey.startsWith(`${key}?`)) return false;\n const query = storageKey.slice(key.length + 1);\n try {\n return stableQueryKey(JSON.parse(query)) === query;\n } catch {\n return false;\n }\n};\n\n/** Deterministic JSON: sorted keys, `undefined` dropped. */\nexport const stableQueryKey = (value: unknown): string =>\n JSON.stringify(value, (_key, item) =>\n item && typeof item === 'object' && !Array.isArray(item)\n ? Object.fromEntries(\n Object.keys(item)\n .sort()\n .filter((key) => item[key] !== undefined)\n .map((key) => [key, item[key]]),\n )\n : item,\n ) ?? '';\n","/**\n * Keys of the queries a fetch adapter runs for a replica. Hosts that sweep\n * their query cache by prefix (e.g. \"refetch everything after a restore\")\n * match on {@link REPLICA_KEY_PREFIX}.\n */\nexport const REPLICA_KEY_PREFIX = 'replica:';\n\nexport const replicaKeys = {\n /** One-shot read of the persisted row for `storageKey`. */\n hydrate: (name: string, version: number, scope: string, storageKey: string) =>\n ['replica:hydrate', name, version, scope, storageKey] as const,\n /** Network sync of the head of one entry. */\n sync: (name: string, version: number, scope: string, key: string, params: unknown) =>\n ['replica:sync', name, version, scope, key, params] as const,\n};\n\n/** Match a resource's sync keys, optionally narrowed to one scope and/or entry key. */\nexport const isReplicaSyncKey = (\n queryKey: unknown,\n name: string,\n filter: { key?: string; scope?: string } = {},\n): boolean =>\n Array.isArray(queryKey) &&\n queryKey[0] === 'replica:sync' &&\n queryKey[1] === name &&\n (filter.scope === undefined || queryKey[3] === filter.scope) &&\n (filter.key === undefined || queryKey[4] === filter.key);\n","import type {\n ReplicaPagedData,\n ReplicaPageResult,\n ReplicaPagingConfig,\n ReplicaPagingContext,\n ReplicaPagingDirection,\n} from './types';\n\n/**\n * First-class pagination for replicas.\n *\n * Vocabulary (direction-agnostic):\n * - HEAD page: the newest window, what a refresh re-fetches (`cursor` undefined).\n * - NEXT pages: further pages in the paging direction (older history).\n * - `forward`: the view is head-first, next pages append at the END\n * (sidebar lists: newest topic first, \"load more\" below).\n * - `backward`: the view is oldest-first, next pages PREPEND at the start\n * (chat transcripts: newest message last, \"load older\" on scroll-up).\n * - `offset` mode: the cursor is the page index (0 = head).\n * `cursor` mode: the server hands back an opaque `nextCursor`.\n *\n * Every function is pure; the store binding owns staleness and scope.\n */\n\nconst dedupe = <TItem>(\n items: TItem[],\n getId: (item: TItem) => string,\n seen = new Set<string>(),\n) => {\n const out: TItem[] = [];\n for (const item of items) {\n const id = getId(item);\n if (seen.has(id)) continue;\n seen.add(id);\n out.push(item);\n }\n return out;\n};\n\nconst ordered = <TItem>(items: TItem[], config: ReplicaPagingConfig<TItem>) =>\n config.sort ? [...items].sort(config.sort) : items;\n\n/** Concatenate in view order: forward = head first, backward = head last. */\nexport const joinPages = <TItem>(\n head: TItem[],\n rest: TItem[],\n direction: ReplicaPagingDirection,\n) => (direction === 'forward' ? [...head, ...rest] : [...rest, ...head]);\n\n/** The paging config one entry reads with: `directionOf` resolved for `key`. */\nexport const pagingFor = <TItem, TCursor>(\n config: ReplicaPagingConfig<TItem, TCursor>,\n key: string,\n) => (config.directionOf ? { ...config, direction: config.directionOf(key) } : config);\n\nconst deriveHasMore = <TItem, TCursor>(\n data: Pick<ReplicaPagedData<TItem, TCursor>, 'items' | 'nextCursor' | 'total'>,\n serverCount: number,\n) => (data.total !== undefined ? data.total > serverCount : data.nextCursor !== null);\n\nconst offsetNext = (more: boolean, nextIndex: number) => (more ? nextIndex : null);\n\n/** Offset mode: whether a page past the loaded ones exists. */\nconst offsetHasMore = <TItem, TCursor>(\n page: ReplicaPageResult<TItem, TCursor>,\n total: number | undefined,\n serverCount: number,\n pageSize: number,\n) => {\n if (page.nextCursor !== undefined) return page.nextCursor !== null;\n return total !== undefined ? total > serverCount : page.items.length >= pageSize;\n};\n\n/**\n * Cursor to request the next page with; `null` → exhausted, `undefined` →\n * cannot page yet. Offset views without bookkeeping (seeded by legacy code or\n * an older persisted shape) derive it from `currentPage` / `hasMore`.\n */\nexport const getNextPageCursor = <TItem, TCursor>(\n data: ReplicaPagedData<TItem, TCursor> | undefined,\n config: Pick<\n ReplicaPagingConfig<TItem, TCursor>,\n 'deriveCursor' | 'direction' | 'isCursorable' | 'mode'\n >,\n): TCursor | null | undefined => {\n if (!data) return undefined;\n if (data.nextCursor !== undefined) return data.nextCursor;\n if (config.mode === 'offset')\n return (data.hasMore ? (data.currentPage ?? 0) + 1 : null) as TCursor | null;\n if (!config.deriveCursor || !data.hasMore) return undefined;\n const boundary = farBoundary(data.items, config);\n return boundary === undefined ? undefined : config.deriveCursor(boundary);\n};\n\n/**\n * The boundary row on the far side of `items` (forward: last, backward: first)\n * that may anchor a join or derive a cursor.\n */\nconst farBoundary = <TItem>(\n items: TItem[],\n config: Pick<ReplicaPagingConfig<TItem>, 'direction' | 'isCursorable'>,\n): TItem | undefined => {\n const eligible = config.isCursorable ?? (() => true);\n if (config.direction === 'forward') return items.findLast((item) => eligible(item));\n return items.find((item) => eligible(item));\n};\n\nconst syntheticIds = <TItem>(\n items: TItem[],\n config: Pick<ReplicaPagingConfig<TItem>, 'getId' | 'isCursorable'>,\n): string[] | undefined => {\n if (!config.isCursorable) return undefined;\n const ids = items.filter((item) => !config.isCursorable!(item)).map(config.getId);\n return ids.length ? ids : undefined;\n};\n\nconst splitClientOnly = <TItem>(items: TItem[], ctx: ReplicaPagingContext<TItem>) => {\n if (!ctx.isClientOnly) return { clientOnly: [] as TItem[], server: items };\n const clientOnly: TItem[] = [];\n const server: TItem[] = [];\n for (const item of items) (ctx.isClientOnly(item) ? clientOnly : server).push(item);\n return { clientOnly, server };\n};\n\n/**\n * Fold a fresh HEAD page into the view.\n *\n * - First load, a query change (`reset`) or an unextended view → the head page.\n * - Extended view, `offset` mode → keep the loaded depth: fresh head first,\n * then previously loaded rows not in it (shifted offsets self-heal by id).\n * - Extended view, `cursor` mode → keep older pages only when the fresh head\n * still contains the join anchor and the next cursor is known; otherwise\n * collapse to the head page (never show a hidden gap).\n *\n * Client-only rows still in the view are kept on the head side.\n */\nexport const applyHeadPage = <TItem, TCursor>(\n current: ReplicaPagedData<TItem, TCursor> | undefined,\n page: ReplicaPageResult<TItem, TCursor>,\n options: { pageSize: number; reset?: boolean },\n config: ReplicaPagingConfig<TItem, TCursor>,\n ctx: ReplicaPagingContext<TItem> = {},\n): ReplicaPagedData<TItem, TCursor> => {\n const { getId, direction } = config;\n const fresh = dedupe(page.items, getId);\n const freshIds = new Set(fresh.map(getId));\n const { clientOnly, server: currentServer } = splitClientOnly(current?.items ?? [], ctx);\n const survivors = clientOnly.filter((item) => !freshIds.has(getId(item)));\n const total = page.total ?? (options.reset ? undefined : current?.total);\n // Client-only rows are the newest: they sit at the very head of the view.\n const headItems = direction === 'forward' ? [...survivors, ...fresh] : [...fresh, ...survivors];\n\n const headOnly = (): ReplicaPagedData<TItem, TCursor> => {\n const nextCursor =\n config.mode === 'offset'\n ? (offsetNext(\n offsetHasMore(page, total, fresh.length, options.pageSize),\n 1,\n ) as TCursor | null)\n : page.nextCursor;\n const data = {\n anchorId: undefined,\n currentPage: 0,\n headSyntheticIds: syntheticIds(fresh, config),\n items: ordered(headItems, config),\n nextCursor,\n pageSize: options.pageSize,\n pages: [{ count: fresh.length, next: nextCursor }],\n total,\n };\n return {\n ...data,\n hasMore: deriveHasMore(data, fresh.length),\n isLoadingMore: current?.isLoadingMore,\n // A fresh head page supersedes the last page failure.\n loadMoreError: undefined,\n };\n };\n\n const extended = !!current && current.currentPage > 0 && !options.reset;\n // A cursor walk keys pages by position, so a head page of another length\n // (round-trimmed windows vary on every refresh) still joins by its anchor.\n if (!extended || (config.mode === 'offset' && current.pageSize !== options.pageSize))\n return headOnly();\n\n let rest: TItem[];\n let anchorId: string | undefined;\n if (config.mode === 'offset') {\n const restCandidates = currentServer.filter((item) => !freshIds.has(getId(item)));\n // Keep the depth the user scrolled to, bounded by what still exists.\n const visible = Math.min(currentServer.length, total ?? Number.POSITIVE_INFINITY);\n const keep = Math.max(0, visible - fresh.length);\n rest =\n direction === 'forward'\n ? restCandidates.slice(0, keep)\n : restCandidates.slice(Math.max(0, restCandidates.length - keep));\n } else {\n const anchorIndex = current.anchorId\n ? currentServer.findIndex((item) => getId(item) === current.anchorId)\n : -1;\n // Without a known next cursor the loaded pages can only be kept when the\n // cursor is derivable from the rows themselves.\n const cursorKnown = current.nextCursor !== undefined || !!config.deriveCursor;\n if (anchorIndex === -1 || !freshIds.has(current.anchorId!) || !cursorKnown) return headOnly();\n const farSide =\n direction === 'forward'\n ? currentServer.slice(anchorIndex + 1)\n : currentServer.slice(0, anchorIndex);\n const staleHead = new Set(current.headSyntheticIds);\n rest = farSide.filter((item) => !freshIds.has(getId(item)) && !staleHead.has(getId(item)));\n const boundary = farBoundary(fresh, config);\n anchorId = boundary ? getId(boundary) : current.anchorId;\n }\n\n const headNext = config.mode === 'cursor' ? page.nextCursor : current.pages?.[0]?.next;\n // A larger head absorbs rows the older pages were counted with; shed the\n // overlap from the pages nearest the head so later trims cut at the boundary.\n let overlap =\n (current.pages ?? []).slice(1).reduce((sum, info) => sum + info.count, 0) - rest.length;\n const olderPages = (current.pages ?? []).slice(1).map((info) => {\n const shed = Math.min(info.count, Math.max(0, overlap));\n overlap -= shed;\n return shed ? { ...info, count: info.count - shed } : info;\n });\n const pages = [{ count: fresh.length, next: headNext }, ...olderPages];\n const data = {\n anchorId: anchorId ?? current.anchorId,\n currentPage: current.currentPage,\n headSyntheticIds: syntheticIds(fresh, config),\n items: ordered(joinPages(headItems, rest, direction), config),\n nextCursor: current.nextCursor,\n pageSize: options.pageSize,\n pages,\n total,\n };\n return {\n ...data,\n hasMore: deriveHasMore(data, fresh.length + rest.length),\n isLoadingMore: current.isLoadingMore,\n loadMoreError: undefined,\n };\n};\n\n/** Merge the NEXT page (fetched with `getNextPageCursor`) into the view. */\nexport const applyNextPage = <TItem, TCursor>(\n current: ReplicaPagedData<TItem, TCursor>,\n page: ReplicaPageResult<TItem, TCursor>,\n config: ReplicaPagingConfig<TItem, TCursor>,\n ctx: ReplicaPagingContext<TItem> = {},\n): ReplicaPagedData<TItem, TCursor> => {\n const { getId, direction } = config;\n const seen = new Set(current.items.map(getId));\n const added = dedupe(page.items, getId, seen);\n const total = page.total ?? current.total;\n const serverCount = splitClientOnly(current.items, ctx).server.length + added.length;\n\n let next: TCursor | null | undefined;\n if (config.mode === 'offset') {\n const more = offsetHasMore(page, total, serverCount, current.pageSize);\n next = offsetNext(more, current.currentPage + 2) as TCursor | null;\n } else {\n // Only an empty page marks the end when the server reports no cursor.\n next = page.items.length === 0 ? null : page.nextCursor;\n }\n\n // The first extension pins the join anchor at the head page's boundary.\n let anchorId = current.anchorId;\n if (current.currentPage === 0) {\n const boundary = farBoundary(splitClientOnly(current.items, ctx).server, config);\n anchorId = boundary ? getId(boundary) : undefined;\n }\n\n const items = ordered(\n direction === 'forward' ? [...current.items, ...added] : [...added, ...current.items],\n config,\n );\n const data = {\n ...current,\n anchorId,\n currentPage: current.currentPage + 1,\n isLoadingMore: false,\n items,\n loadMoreError: undefined,\n nextCursor: next,\n pages: [\n ...(current.pages?.length ? current.pages : [{ count: current.items.length }]),\n { count: added.length, next },\n ],\n total,\n };\n return { ...data, hasMore: deriveHasMore(data, serverCount) };\n};\n\n/**\n * Insert new rows on the HEAD side (a streamed message, a created topic).\n * Cursors point at the far end, so they stay valid; offsets shift and are\n * healed by id de-duplication on the next page merge.\n */\nexport const insertHeadItems = <TItem, TCursor>(\n current: ReplicaPagedData<TItem, TCursor>,\n items: TItem[],\n config: ReplicaPagingConfig<TItem, TCursor>,\n): ReplicaPagedData<TItem, TCursor> => {\n const seen = new Set(current.items.map(config.getId));\n const added = dedupe(items, config.getId, seen);\n if (added.length === 0) return current;\n const pages = current.pages?.length ? current.pages : [{ count: current.items.length }];\n return {\n ...current,\n items: ordered(joinPages(added, current.items, config.direction), config),\n pages: [{ ...pages[0], count: pages[0].count + added.length }, ...pages.slice(1)],\n total: current.total === undefined ? undefined : current.total + added.length,\n };\n};\n\n/**\n * Patch (or remove, when `fn` returns `undefined`) one row by id. Returns the\n * same reference when the row is absent or unchanged.\n */\nexport const mapPagedItem = <TItem, TCursor, TData extends ReplicaPagedData<TItem, TCursor>>(\n current: TData,\n id: string,\n fn: (item: TItem) => TItem | undefined,\n config: Pick<ReplicaPagingConfig<TItem>, 'getId'>,\n): TData => {\n const index = current.items.findIndex((item) => config.getId(item) === id);\n if (index === -1) return current;\n const next = fn(current.items[index]);\n if (next === current.items[index]) return current;\n if (next !== undefined) {\n const items = [...current.items];\n items[index] = next;\n return { ...current, items };\n }\n const items = current.items.filter((_, i) => i !== index);\n const total = current.total === undefined ? undefined : Math.max(items.length, current.total - 1);\n return {\n ...current,\n hasMore: total !== undefined ? total > items.length : current.hasMore,\n items,\n total,\n };\n};\n\n/** Whether a paged view holds a row. */\nexport const hasPagedItem = <TItem>(\n data: ReplicaPagedData<TItem, unknown> | undefined,\n id: string,\n config: Pick<ReplicaPagingConfig<TItem>, 'getId'>,\n) => !!data?.items.some((item) => config.getId(item) === id);\n\n/** Select head-side rows without losing synthetic head rows sorted among older pages. */\nconst takeHeadItems = <TItem, TCursor>(\n items: TItem[],\n count: number,\n data: ReplicaPagedData<TItem, TCursor>,\n config: ReplicaPagingConfig<TItem, TCursor>,\n): TItem[] => {\n if (count === 0) return [];\n const synthetic = new Set(data.headSyntheticIds);\n const syntheticCount = items.filter((item) => synthetic.has(config.getId(item))).length;\n const regular = items.filter((item) => !synthetic.has(config.getId(item)));\n const regularCount = Math.max(0, count - syntheticCount);\n const selected =\n config.direction === 'forward'\n ? regular.slice(0, regularCount)\n : regular.slice(Math.max(0, regular.length - regularCount));\n const ids = new Set(selected.map(config.getId));\n return items\n .filter((item) => synthetic.has(config.getId(item)) || ids.has(config.getId(item)))\n .slice(\n config.direction === 'forward' ? 0 : -count,\n config.direction === 'forward' ? count : undefined,\n );\n};\n\n/** Drop every loaded page but the head (e.g. after an edit inside older history). */\nexport const collapseToHead = <TItem, TCursor>(\n current: ReplicaPagedData<TItem, TCursor>,\n config: ReplicaPagingConfig<TItem, TCursor>,\n): ReplicaPagedData<TItem, TCursor> => {\n if (current.currentPage === 0) return current;\n const head = current.pages?.[0];\n const count = head?.count ?? current.pageSize;\n const items = takeHeadItems(current.items, count, current, config);\n const nextCursor = config.mode === 'offset' ? (1 as TCursor) : (head?.next ?? undefined);\n return {\n ...current,\n anchorId: undefined,\n currentPage: 0,\n hasMore: true,\n items,\n nextCursor,\n pages: [{ count: items.length, next: nextCursor }],\n };\n};\n\n/**\n * What survives a reload: whole pages from the head side, bounded by\n * `persist.pages` and `persist.maxItems`, client-only rows and transient\n * flags stripped. Offset views are cut at page-size boundaries so the\n * persisted `currentPage` stays a valid offset; a cut inside a cursor page\n * forgets the cursor (pagination resumes after the next server head page).\n */\nexport const toPersistedPage = <TItem, TCursor, TData extends ReplicaPagedData<TItem, TCursor>>(\n data: TData,\n config: ReplicaPagingConfig<TItem, TCursor>,\n ctx: ReplicaPagingContext<TItem> = {},\n): TData => {\n const { server } = splitClientOnly(data.items, ctx);\n const pageLimit = Math.max(1, config.persist?.pages ?? 1);\n const maxItems = config.persist?.maxItems ?? Number.POSITIVE_INFINITY;\n // The head page absorbs every row written since it was fetched (a sent\n // message, a streamed reply): older pages keep their fetched size, so the\n // head is whatever they do not account for.\n const olderCount = (data.pages ?? []).slice(1).reduce((sum, page) => sum + page.count, 0);\n const pages = data.pages?.length\n ? [{ ...data.pages[0], count: Math.max(0, server.length - olderCount) }, ...data.pages.slice(1)]\n : [{ count: server.length, next: data.nextCursor }];\n\n let count = 0;\n let keptPages = 0;\n let aligned = true;\n if (config.mode === 'offset') {\n const loadedPages = Math.min(pageLimit, data.currentPage + 1);\n const byItems = Math.floor(maxItems / Math.max(1, data.pageSize));\n keptPages = Math.max(1, Math.min(loadedPages, byItems || 1));\n count = Math.min(server.length, keptPages * data.pageSize, maxItems);\n } else {\n for (const page of pages.slice(0, pageLimit)) {\n if (count + page.count > maxItems) {\n aligned = false;\n count = keptPages === 0 ? Math.min(page.count, maxItems) : count;\n if (keptPages === 0) keptPages = 1;\n break;\n }\n count += page.count;\n keptPages += 1;\n }\n count = Math.min(count, server.length);\n }\n\n const items = takeHeadItems(server, count, data, config);\n const lastKept = pages[keptPages - 1];\n const nextCursor =\n config.mode === 'offset'\n ? ((count < (data.total ?? server.length) ||\n // Every loaded row survives: the server's own verdict on the page past\n // them still holds (a filtered short page is not necessarily the end).\n (count === server.length && data.total === undefined && data.nextCursor != null)\n ? keptPages\n : null) as TCursor | null)\n : aligned\n ? lastKept?.next\n : undefined;\n\n const {\n isLoadingMore: _loading,\n loadMoreError: _error,\n ...rest\n } = data as ReplicaPagedData<TItem, TCursor>;\n return {\n ...rest,\n anchorId: keptPages > 1 ? data.anchorId : undefined,\n currentPage: keptPages - 1,\n hasMore: data.total !== undefined ? data.total > items.length : nextCursor !== null,\n items,\n nextCursor,\n pages: [\n ...pages.slice(0, keptPages - 1),\n {\n count: Math.max(\n 0,\n items.length - pages.slice(0, keptPages - 1).reduce((sum, page) => sum + page.count, 0),\n ),\n next: nextCursor,\n },\n ],\n } as unknown as TData;\n};\n","import type { ReplicaRow, ReplicaRowKey, ReplicaStorage } from '../../storage/types';\n\n/**\n * Strict read of one row (see `ReplicaStorage.getStrict`). Rejects when the\n * storage has no strict read: its `get` swallows I/O failures into a miss, so a\n * destructive pass reading through it could take an unreadable row (the index)\n * for an empty one and report success for rows it never saw.\n */\nexport const readReplicaRowStrict = <T>(\n storage: ReplicaStorage<T>,\n key: ReplicaRowKey,\n): Promise<ReplicaRow<T> | undefined> =>\n // Call through `storage`: a class-based storage needs its receiver.\n storage.getStrict\n ? storage.getStrict(key)\n : Promise.reject(\n new Error('[replica] storage has no `getStrict`: destructive passes are disabled'),\n );\n\n/**\n * Serializes writes for one projection key. A later snapshot can never be overwritten by an\n * earlier, slower IndexedDB write.\n */\nexport class ReplicaWriteQueue<T> {\n readonly #pending = new Map<string, Promise<void>>();\n readonly #storage: ReplicaStorage<T>;\n\n constructor(storage: ReplicaStorage<T>) {\n this.#storage = storage;\n }\n\n #id = ({ queryKey, scope }: ReplicaRowKey) => `${scope}:${queryKey}`;\n\n /** Resolves `false` when storage rejected the delete (see `ReplicaStorage.remove`). */\n remove = (key: ReplicaRowKey): Promise<boolean> =>\n this.#enqueue(key, () => this.#storage.remove(key));\n\n set = (key: ReplicaRowKey, value: ReplicaRow<T>): Promise<boolean> =>\n this.#enqueue(key, () => this.#storage.set(key, value));\n\n /**\n * Serialized read-modify-write: `fn` sees the row as of every earlier queued\n * write for this key. Return a projection to write it, `null` to remove the\n * row, or `undefined` to leave it untouched (a missing row stays missing).\n *\n * `read` picks how the row is read:\n * - `'get'` (default): best-effort `get`, a failed read passes for a miss.\n * - `'prefer-strict'`: `getStrict` when the storage has one, so a read failure\n * fails the update (resolves `false`) instead of passing for a missing row\n * that `fn` would then overwrite; `get` otherwise.\n * - `'strict'`: `getStrict` only; a storage without it fails the update.\n * Required for destructive passes (see `readReplicaRowStrict`).\n */\n update = (\n key: ReplicaRowKey,\n fn: (current: ReplicaRow<T> | undefined) => ReplicaRow<T> | null | undefined,\n { read = 'get' }: { read?: 'get' | 'prefer-strict' | 'strict' } = {},\n ): Promise<boolean> =>\n this.#enqueue(key, async () => {\n const storage = this.#storage;\n const strict = read === 'strict' || (read === 'prefer-strict' && !!storage.getStrict);\n const current = await (strict ? readReplicaRowStrict(storage, key) : storage.get(key));\n const next = fn(current);\n if (next === null) await this.#storage.remove(key);\n else if (next !== undefined) await this.#storage.set(key, next);\n });\n\n /**\n * Queue `operation` behind the earlier writes for this key and report whether\n * it settled successfully. A failed write never rejects the returned promise:\n * the caller decides what to do (e.g. keep a removal retryable), while a\n * rejection on the queue itself is already swallowed so one bad write cannot\n * poison the chain.\n */\n #enqueue = (key: ReplicaRowKey, operation: () => Promise<void>): Promise<boolean> => {\n const id = this.#id(key);\n const previous = this.#pending.get(id) ?? Promise.resolve();\n const current = previous.catch(() => undefined).then(operation);\n this.#pending.set(id, current);\n const settled = current.then(\n () => true,\n () => false,\n );\n void settled.finally(() => {\n if (this.#pending.get(id) === current) this.#pending.delete(id);\n });\n return settled;\n };\n}\n","import isEqual from 'fast-deep-equal';\n\nimport { isReplicaStorageKeyOf, replicaStorageKey } from '../resource/storageKey';\nimport type { ReplicaResource } from '../resource/types';\nimport type { ReplicaState } from '../state/types';\nimport { readReplicaRowStrict, type ReplicaWriteQueue } from './writeQueue';\n\n/** Reserved storage key of the per-scope index of persisted rows. */\nexport const REPLICA_INDEX_KEY = '__replica:index';\n\nexport interface ReplicaPersistedRowsDeps<TData> {\n /** Drop evicted entries from the host view (one commit). */\n commit: (keys: string[], state: ReplicaState<TData>) => void;\n getSlot: () => ReplicaState<TData>;\n /** Whether `scope`/`key` is guarded as removed (see `createRemovalGuards`). */\n isRemoved: (scope: string, key: string) => boolean;\n /** Keys with a `loadMore` request in flight (pinned against eviction). */\n loadingMore: ReadonlySet<string>;\n resource: ReplicaResource<any, TData, any>;\n writeQueue: ReplicaWriteQueue<TData> | undefined;\n}\n\n/** Returned by a `patchRow` transform to delete the row (`null` stays a value). */\nexport const DROP_ROW = Symbol('replica.dropRow');\n\n/**\n * Bookkeeping of the rows one engine persisted: the per-scope index, the latest\n * queued write per row, what each row is known to hold, and the bounded\n * (`persist.maxEntries`) eviction. Every row write and delete of the engine\n * goes through here, so the index never misses or resurrects a row.\n */\nexport const createPersistedRows = <TData>({\n commit,\n getSlot,\n isRemoved,\n loadingMore,\n resource,\n writeQueue,\n}: ReplicaPersistedRowsDeps<TData>) => {\n // ---- persisted-row index ---------------------------------------------\n // Storage has no key listing, so each scope keeps an index row of the\n // storage keys this resource persisted. Entity changes use it to patch rows\n // whose entry is not loaded in memory (e.g. a status update for a list the\n // user navigated away from), so a later visit never hydrates a stale value.\n const indexKey = (scope: string) => ({ queryKey: REPLICA_INDEX_KEY, scope });\n /** Keys known to be in the index row, per scope (skips redundant index writes). */\n const indexed = new Map<string, Set<string>>();\n const indexedKeys = (scope: string) => indexed.get(scope);\n\n /**\n * Latest queued write per row (`scope` + storage key), from one monotonic\n * counter. A confirmed delete only takes its key out of the index when no\n * later write re-created the row in the meantime.\n */\n const rowWrites = new Map<string, number>();\n let writeCounter = 0;\n const writeCount = () => writeCounter;\n const rowId = (scope: string, queryKey: string) => `${scope}\\u0000${queryKey}`;\n const noteWrite = (scope: string, queryKey: string) => {\n const seq = ++writeCounter;\n rowWrites.set(rowId(scope, queryKey), seq);\n return seq;\n };\n\n // ---- last persisted value per row ---------------------------------------\n // What this session knows a row holds in storage: the value of its latest\n // write once that write is confirmed (`ReplicaStorage.set` resolved), or the\n // value read back by a hydrate no write raced. A write still in flight, or one\n // that failed, leaves the row unknown. A persist of a\n // deep-equal value is skipped — an unchanged revalidation must not rewrite\n // the same row. Every path that may change a row behind it (a delete, a\n // patch, a clear, an eviction) forgets the row, so the next persist writes.\n const storedValues = new Map<string, Map<string, unknown>>();\n const rememberStored = (scope: string, queryKey: string, data: unknown) => {\n const rows = storedValues.get(scope) ?? new Map<string, unknown>();\n storedValues.set(scope, rows);\n rows.set(queryKey, data);\n };\n const forgetStored = (scope: string, queryKeys: Iterable<string>) => {\n const rows = storedValues.get(scope);\n if (!rows) return;\n for (const queryKey of queryKeys) rows.delete(queryKey);\n if (rows.size === 0) storedValues.delete(scope);\n };\n /** Forget every row of `scope` (memory moved to another identity, or a clear). */\n const forgetScope = (scope: string) => {\n storedValues.delete(scope);\n };\n const isStored = (scope: string, queryKey: string, data: unknown) => {\n const rows = storedValues.get(scope);\n return !!rows?.has(queryKey) && isEqual(rows.get(queryKey), data);\n };\n /**\n * A hydrate read `data` back from the row: the row holds it, unless a write\n * was queued while reading (`writesBefore` is `writeCount()` before the read).\n */\n const rememberRead = (scope: string, queryKey: string, data: unknown, writesBefore: number) => {\n if (writeCounter === writesBefore && !storedValues.get(scope)?.has(queryKey))\n rememberStored(scope, queryKey, data);\n };\n\n // ---- bounded persisted entries ----------------------------------------\n // With `persist.maxEntries`, the index is kept in least-recently-used order\n // (oldest first — the order an unbounded index is appended in, so rows an\n // earlier release indexed keep their place) and every use of a row moves it\n // to the end. Past the cap the oldest rows that nothing pins are evicted.\n const maxEntries = resource.maxPersistedEntries;\n /** Mounted readers per storage key and per entry key (see `retain`). */\n const retainedRows = new Map<string, number>();\n const retainedKeys = new Map<string, number>();\n /** Rows whose eviction delete is queued, per scope. */\n const evicting = new Map<string, Set<string>>();\n\n const bump = (counts: Map<string, number>, id: string, by: number) => {\n const next = (counts.get(id) ?? 0) + by;\n if (next > 0) counts.set(id, next);\n else counts.delete(id);\n };\n\n /**\n * Pin an entry (and the row of the query it asks for) while something shows\n * it: eviction never drops a retained row or the memory entry of a retained\n * key. `useSync` retains for as long as it is mounted. Returns the release.\n */\n const retain = (key: string, queryKey: string = replicaStorageKey(key)) => {\n bump(retainedKeys, key, 1);\n bump(retainedRows, queryKey, 1);\n let released = false;\n return () => {\n if (released) return;\n released = true;\n bump(retainedKeys, key, -1);\n bump(retainedRows, queryKey, -1);\n };\n };\n\n /** Rows the memory of `scope` holds, by storage key → entry key. */\n const loadedRows = (scope: string) => {\n const slot = getSlot();\n const rows = new Map<string, string>();\n if (slot.scope !== scope) return rows;\n for (const [key, entry] of Object.entries(slot.entries))\n rows.set(replicaStorageKey(key, entry.query), key);\n return rows;\n };\n\n /**\n * A row on screen, or whose entry has writes / a page load in flight.\n * `entryKey` comes from `loadedRows`, so its entry is in the slot.\n */\n const isPinned = (queryKey: string, entryKey: string | undefined) =>\n retainedRows.has(queryKey) ||\n (entryKey !== undefined &&\n (retainedKeys.has(entryKey) ||\n getSlot().entries[entryKey].pending.length > 0 ||\n loadingMore.has(entryKey)));\n\n /** The oldest unpinned rows past the cap (`keys` is oldest first). */\n const pickEvictions = (scope: string, keys: string[], touched: string): string[] => {\n const going = evicting.get(scope);\n let excess = keys.length - maxEntries! - keys.filter((key) => going?.has(key)).length;\n if (excess <= 0) return [];\n const loaded = loadedRows(scope);\n const picked: string[] = [];\n for (const queryKey of keys) {\n if (excess <= 0) break;\n if (queryKey === touched || going?.has(queryKey)) continue;\n if (isPinned(queryKey, loaded.get(queryKey))) continue;\n picked.push(queryKey);\n excess -= 1;\n }\n return picked;\n };\n\n /**\n * Evict rows: drop the memory entries that answer them (one commit), then\n * delete the rows. A row leaves the index only once its delete landed, so a\n * failed eviction is picked again by a later use.\n */\n const evictRows = (scope: string, queryKeys: string[]) => {\n if (resource.scope.get() !== scope || !resource.scope.canPersist()) return;\n const going = evicting.get(scope) ?? new Set<string>();\n evicting.set(scope, going);\n const loaded = loadedRows(scope);\n // Re-check: a row may have been pinned since it was picked.\n const rows = queryKeys.filter(\n (queryKey) => !going.has(queryKey) && !isPinned(queryKey, loaded.get(queryKey)),\n );\n if (rows.length === 0) return;\n for (const queryKey of rows) going.add(queryKey);\n const dropped = rows.flatMap((queryKey) => {\n const key = loaded.get(queryKey);\n return key === undefined ? [] : [key];\n });\n if (dropped.length > 0) {\n const slot = getSlot();\n const entries = { ...slot.entries };\n for (const key of dropped) delete entries[key];\n commit(dropped, { entries, scope });\n }\n void deleteRows(scope, rows).finally(() => {\n for (const queryKey of rows) going.delete(queryKey);\n if (going.size === 0 && evicting.get(scope) === going) evicting.delete(scope);\n });\n };\n\n /**\n * A bounded resource used a row: move it to the end of the index and evict\n * past the cap. No-op for an unbounded resource.\n */\n const touchStorageKey = (scope: string, queryKey: string) => {\n if (!writeQueue || maxEntries === undefined) return;\n const known = indexed.get(scope) ?? new Set<string>();\n indexed.set(scope, known);\n known.add(queryKey);\n let picked: string[] = [];\n void writeQueue\n .update(\n indexKey(scope),\n (current) => {\n const keys = (current?.data as unknown as string[] | undefined) ?? [];\n const next = [...keys.filter((key) => key !== queryKey), queryKey];\n picked = pickEvictions(scope, next, queryKey);\n if (keys.length === next.length && keys.at(-1) === queryKey) return undefined;\n return { data: next as unknown as TData, updatedAt: Date.now() };\n },\n { read: 'prefer-strict' },\n )\n .then((touched) => {\n // Unreadable index: leave it untouched, retry the append on the next use.\n if (!touched) return void known.delete(queryKey);\n if (picked.length > 0) evictRows(scope, picked);\n });\n };\n\n /** Record a persisted row in the index (queued after the row write; see `writeRow`). */\n const trackStorageKey = (scope: string, queryKey: string) => {\n noteWrite(scope, queryKey);\n if (maxEntries !== undefined) return touchStorageKey(scope, queryKey);\n const known = indexed.get(scope) ?? new Set<string>();\n indexed.set(scope, known);\n if (known.has(queryKey)) return;\n known.add(queryKey);\n void writeQueue!\n .update(\n indexKey(scope),\n (current) => {\n const keys = new Set((current?.data as unknown as string[] | undefined) ?? []);\n if (keys.has(queryKey)) return undefined;\n keys.add(queryKey);\n return { data: [...keys] as unknown as TData, updatedAt: Date.now() };\n },\n { read: 'prefer-strict' },\n )\n // An unreadable index is left untouched (never rewritten as just this\n // key); forget the key so the next write of the row retries the append.\n .then((tracked) => {\n if (!tracked) known.delete(queryKey);\n });\n };\n\n /**\n * Read the index for a destructive pass (remove / clear / entity patch).\n * Uses the storage's strict read when it has one, so an unreadable index\n * rejects instead of looking empty — a purge must never report success for\n * rows it could not enumerate.\n */\n const readIndex = async (scope: string): Promise<string[]> => {\n // A storage without `getStrict` rejects here: its `get` cannot tell an\n // unreadable index from an empty one.\n const row = await readReplicaRowStrict(resource.storage!, indexKey(scope));\n return (row?.data as unknown as string[] | undefined) ?? [];\n };\n\n /**\n * Drop storage keys from the index (both the session's view of it and the\n * persisted row, which may list keys this session never wrote).\n */\n const untrackStorageKeys = (scope: string, queryKeys: string[]) => {\n if (!writeQueue || queryKeys.length === 0) return;\n const known = indexed.get(scope);\n for (const queryKey of queryKeys) known?.delete(queryKey);\n const dropped = new Set(queryKeys);\n writeQueue.update(\n indexKey(scope),\n (current) => {\n const keys = (current?.data as unknown as string[] | undefined) ?? [];\n const next = keys.filter((queryKey) => !dropped.has(queryKey));\n if (!current || next.length === keys.length) return undefined;\n return { data: next as unknown as TData, updatedAt: Date.now() };\n },\n { read: 'prefer-strict' },\n );\n };\n\n /** Take rows whose delete landed out of the index, unless rewritten since. */\n const confirmDeleted = (scope: string, deleted: [queryKey: string, seq: number][]) => {\n const gone = deleted\n .filter(([queryKey, seq]) => rowWrites.get(rowId(scope, queryKey)) === seq)\n .map(([queryKey]) => queryKey);\n for (const queryKey of gone) rowWrites.delete(rowId(scope, queryKey));\n untrackStorageKeys(scope, gone);\n };\n\n /**\n * Queue row deletes now (ordered before any later write to the same rows).\n * A key leaves the index only once its delete is confirmed: a failed delete\n * stays indexed, so the next `remove` / `clear` finds and retries it.\n * Resolves `true` when every delete landed.\n */\n const deleteRows = (scope: string, queryKeys: string[]): Promise<boolean> => {\n const queue = writeQueue!;\n forgetStored(scope, queryKeys);\n const queued = queryKeys.map((queryKey) => {\n const seq = noteWrite(scope, queryKey);\n return queue\n .remove({ queryKey, scope })\n .then((removed): [string, number] | undefined => (removed ? [queryKey, seq] : undefined));\n });\n return Promise.all(queued).then((results) => {\n confirmDeleted(\n scope,\n results.filter((result): result is [string, number] => !!result),\n );\n return results.every(Boolean);\n });\n };\n\n /**\n * Delete every persisted row of entry `key` in `scope` — `current` (the row\n * memory knows about, queued right away so it orders before any later write)\n * plus every other query variant the index lists. Resolves `true` once all\n * deletes landed.\n */\n const removeStoredVariants = (scope: string, key: string, current: string) => {\n const first = deleteRows(scope, [current]);\n const rest = readIndex(scope).then(\n (persisted) => {\n // A server value that superseded the removal while the index was read\n // owns its (fresh) row: keep it, delete only the stale variants.\n const slot = getSlot();\n const live = !isRemoved(scope, key) && slot.scope === scope ? slot.entries[key] : undefined;\n const liveKey = live && replicaStorageKey(key, live.query);\n const variants = new Set(\n [...(indexed.get(scope) ?? []), ...persisted].filter(\n (queryKey) =>\n queryKey !== current && queryKey !== liveKey && isReplicaStorageKeyOf(queryKey, key),\n ),\n );\n return variants.size === 0 ? true : deleteRows(scope, [...variants]);\n },\n () => false,\n );\n return Promise.all([first, rest]).then((results) => results.every(Boolean));\n };\n\n /** Persist `data` to one row (the write path of a `persist` effect). */\n const writeRow = (scope: string, queryKey: string, data: TData) => {\n const queue = writeQueue!;\n // The row already holds this value: an unchanged revalidation is no write.\n if (isStored(scope, queryKey, data)) {\n touchStorageKey(scope, queryKey);\n return;\n }\n // Until this write is confirmed the row's content is unknown: forget what\n // it held, and only remember `data` once the write observably landed and\n // is still the latest queued for the row. A failed (or best-effort,\n // silently dropped) write therefore never makes a later identical persist\n // look redundant — that one writes again.\n forgetStored(scope, [queryKey]);\n trackStorageKey(scope, queryKey);\n const id = rowId(scope, queryKey);\n const seq = rowWrites.get(id);\n void queue.set({ queryKey, scope }, { data, updatedAt: Date.now() }).then((written) => {\n if (written && rowWrites.get(id) === seq) rememberStored(scope, queryKey, data);\n });\n };\n\n /**\n * Read-modify-write one row in the per-key write queue, so it sees every\n * earlier write; a missing row is never recreated. `transform` returns the\n * next data, `undefined` to leave the row, or `DROP_ROW` to drop it (the row\n * leaves the index once its delete landed). Resolves whether it settled.\n */\n const patchRow = (\n scope: string,\n queryKey: string,\n transform: (data: TData) => TData | typeof DROP_ROW | undefined,\n ): Promise<boolean> => {\n const seq = noteWrite(scope, queryKey);\n forgetStored(scope, [queryKey]);\n let dropped = false;\n return writeQueue!\n .update(\n { queryKey, scope },\n (current) => {\n if (!current) return undefined;\n const next = transform(current.data);\n if (next === undefined) return undefined;\n if (next === DROP_ROW) {\n dropped = true;\n return null;\n }\n return { data: next, updatedAt: Date.now() };\n },\n { read: 'strict' },\n )\n .then((written) => {\n if (written && dropped) confirmDeleted(scope, [[queryKey, seq]]);\n return written;\n });\n };\n\n /**\n * Read-modify-write the persisted rows memory does not hold, keyed by row\n * rather than by entity: a cached list for a folder the user is not viewing\n * gets its projection patched in the per-key write queue, so a later visit\n * hydrates the reconciled value instead of a stale page. `fn` returns the\n * next data, the same reference (or `undefined`) to skip, or `null` to drop\n * the row. Runs in the write queue, so it sees every earlier write.\n */\n const patchStoredRows = async (fn: (data: TData) => TData | null | undefined): Promise<void> => {\n if (!writeQueue || !resource.scope.canPersist()) return;\n const scope = resource.scope.get();\n const slot = getSlot();\n const loaded = new Set(\n slot.scope === scope\n ? Object.entries(slot.entries).map(([key, entry]) => replicaStorageKey(key, entry.query))\n : [],\n );\n let keys: string[];\n try {\n keys = await readIndex(scope);\n } catch (error) {\n console.error(`[replica:${resource.name}] failed to read the persisted index`, error);\n return;\n }\n // Identity changed while reading the index: those rows are not ours to touch.\n if (resource.scope.get() !== scope) return;\n const patches: Promise<boolean>[] = [];\n for (const queryKey of keys) {\n if (loaded.has(queryKey)) continue;\n patches.push(\n patchRow(scope, queryKey, (data) => {\n const next = fn(data);\n if (next === data) return undefined;\n return next === null ? DROP_ROW : next;\n }),\n );\n }\n await Promise.all(patches);\n };\n\n return {\n deleteRows,\n forgetScope,\n forgetStored,\n indexedKeys,\n patchRow,\n patchStoredRows,\n readIndex,\n rememberRead,\n removeStoredVariants,\n retain,\n touchStorageKey,\n writeCount,\n writeRow,\n };\n};\n\nexport type ReplicaPersistedRows<TData> = ReturnType<typeof createPersistedRows<TData>>;\n","import type { ReplicaEntityRemovalGuards } from '../engine/removalGuards';\nimport type { ReplicaOptimisticToken, ReplicaStorePort } from '../engine/types';\nimport { hasPagedItem, mapPagedItem } from '../paging/operations';\nimport type { ReplicaPagedData, ReplicaPagingConfig } from '../paging/types';\nimport { DROP_ROW, type ReplicaPersistedRows } from '../persistence/persistedRows';\nimport { replicaStorageKey } from '../resource/storageKey';\nimport type { ReplicaResource } from '../resource/types';\nimport type { ReplicaSource, ReplicaState } from '../state/types';\nimport type { ReplicaEntityAdapter } from './types';\n\nexport interface ReplicaEntityPropagationDeps<TData> {\n beginOptimistic: (key: string, apply: (data: TData) => TData) => ReplicaOptimisticToken<TData>;\n /** Non-paged resources: how entities sit in the value. */\n entity?: ReplicaEntityAdapter<TData, any>;\n entityGuards: ReplicaEntityRemovalGuards;\n getSlot: () => ReplicaState<TData>;\n paging?: ReplicaPagingConfig<any, any>;\n port: ReplicaStorePort<TData>;\n remove: (key: string) => boolean;\n resource: ReplicaResource<any, TData, any>;\n rows: ReplicaPersistedRows<TData>;\n update: (\n key: string,\n apply: (data: TData | undefined) => TData | undefined,\n options?: { persist?: boolean; seedTag?: string; source?: ReplicaSource },\n ) => boolean;\n}\n\n/**\n * Entity propagation: a change to one entity (e.g. a topic) applied to every\n * entry that holds it — in memory, in persisted rows memory does not hold,\n * and in rows a hydrate reads back while a removal is still landing.\n */\nexport const createEntityPropagation = <TData>({\n beginOptimistic,\n entity,\n entityGuards,\n getSlot,\n paging,\n port,\n remove,\n resource,\n rows,\n update,\n}: ReplicaEntityPropagationDeps<TData>) => {\n const entityKeys = (id: string): string[] => {\n const keys = port.keys?.() ?? Object.keys(getSlot().entries);\n return keys.filter((key) => {\n const data = port.read(key);\n if (data === undefined) return false;\n if (paging) return hasPagedItem(data as any, id, paging);\n return entity ? entity.has(data, id) : false;\n });\n };\n\n /** Map one entity inside a value; `undefined` means the whole value goes away. */\n const mapEntity = <TItem>(\n data: TData,\n id: string,\n fn: (item: TItem) => TItem | undefined,\n ): TData | undefined => {\n if (paging) return mapPagedItem(data as any, id, fn as any, paging) as TData;\n if (!entity || !entity.has(data, id)) return data;\n return entity.map(data, id, fn);\n };\n\n /** Which of `ids` are held by `data`. */\n const heldEntities = (data: TData, ids: string[]): string[] => {\n if (paging) {\n const items = (data as unknown as ReplicaPagedData<unknown, unknown>).items ?? [];\n const present = new Set(items.map((item) => paging.getId(item)));\n return ids.filter((id) => present.has(id));\n }\n return entity ? ids.filter((id) => entity.has(data, id)) : [];\n };\n\n /** Strip entities removed in `scope` from a value read back from storage. */\n const withoutRemovedEntities = (scope: string, data: TData): TData | undefined => {\n const removed = entityGuards.removedIds(scope);\n if (removed.length === 0) return data;\n let next: TData | undefined = data;\n for (const id of heldEntities(data, removed)) {\n next = mapEntity(next!, id, () => undefined);\n if (next === undefined) break;\n }\n return next;\n };\n\n /** A server value holding a removed entity again (restored) lifts its guard. */\n const forgetRestoredEntities = (scope: string, data: TData | undefined) => {\n const removed = entityGuards.removedIds(scope);\n if (removed.length === 0 || data === undefined) return;\n entityGuards.liftEntityGuards(scope, heldEntities(data, removed));\n };\n\n /**\n * Apply an entity change to persisted rows that memory does not hold (the\n * memory path already persists loaded entries). Read-modify-write runs in\n * the per-key write queue, so it sees every earlier write; a missing row is\n * never recreated. Resolves once the patches have settled: `true` when every\n * unloaded row is known to be patched (or nothing is persisted), `false` when\n * a row may still hold the old entity (untrusted scope, unreadable index or\n * row, a failed write, an identity switch mid-pass).\n */\n const patchStoredEntityRows = async <TItem>(\n id: string,\n fn: (item: TItem) => TItem | undefined,\n scope: string = resource.scope.get(),\n ): Promise<boolean> => {\n if (!resource.storage) return true;\n if (!resource.scope.canPersist()) return false;\n // A scope left behind is patched on purpose: nothing of it is loaded, and an\n // identity switch while reading its index does not make its rows foreign.\n const offScope = scope !== resource.scope.get();\n const slot = getSlot();\n // Rows memory holds are patched through memory — but only in the active\n // scope; a view still showing a scope left behind is not what it persists.\n const loaded = new Set(\n !offScope && slot.scope === scope\n ? Object.entries(slot.entries).map(([key, entry]) => replicaStorageKey(key, entry.query))\n : [],\n );\n let keys: string[];\n try {\n keys = await rows.readIndex(scope);\n } catch (error) {\n // Rows cannot be enumerated: nothing to patch. Loaded entries are already\n // updated, and a removal keeps guarding later hydrates (`removeEntity`).\n console.error(`[replica:${resource.name}] failed to read the persisted index`, error);\n return false;\n }\n // Identity changed while reading the index: those rows are not ours to touch.\n if (!offScope && resource.scope.get() !== scope) return false;\n // Rows this session wrote to the scope may not be in the persisted index yet\n // (their row or index write is still queued — e.g. just before an account\n // switch). Patch them too: each patch is queued behind the row's own write,\n // so it reads the row once that write landed.\n for (const queryKey of rows.indexedKeys(scope) ?? [])\n if (!keys.includes(queryKey)) keys.push(queryKey);\n const patches: Promise<boolean>[] = [];\n for (const queryKey of keys) {\n if (loaded.has(queryKey)) continue;\n patches.push(\n rows.patchRow(scope, queryKey, (data) => {\n const next = mapEntity(data, id, fn);\n if (next === data) return undefined;\n return next === undefined ? DROP_ROW : next;\n }),\n );\n }\n return (await Promise.all(patches)).every(Boolean);\n };\n\n const patchStoredEntity = async <TItem>(\n id: string,\n fn: (item: TItem) => TItem | undefined,\n ): Promise<void> => {\n await patchStoredEntityRows(id, fn);\n };\n\n /**\n * `updateEntity`, returning the persisted-row patch (if any) to wait on —\n * `true` once every unloaded row is patched.\n */\n const applyEntity = <TItem>(\n id: string,\n fn: (item: TItem) => TItem | undefined,\n { persist = true }: { persist?: boolean } = {},\n ): Promise<boolean> | undefined => {\n const patch = persist ? patchStoredEntityRows(id, fn) : undefined;\n for (const key of entityKeys(id)) {\n const current = port.read(key);\n if (current === undefined) continue;\n const next = mapEntity(current, id, fn);\n if (next === undefined) remove(key);\n else\n update(key, (data) => (data === undefined ? data : (mapEntity(data, id, fn) ?? data)), {\n persist,\n });\n }\n return patch;\n };\n\n /**\n * An entity patch started for a scope that was not active settled. If the\n * user switched back to that scope meanwhile, an entry may have hydrated the\n * pre-patch row before the patch landed: apply the same change to what is\n * loaded now, in memory only — storage already holds it.\n */\n const reconcileLoaded = <TItem>(\n scope: string,\n id: string,\n fn: (item: TItem) => TItem | undefined,\n ) => {\n if (resource.scope.get() !== scope || getSlot().scope !== scope) return;\n for (const key of entityKeys(id)) {\n const current = port.read(key);\n if (current === undefined) continue;\n // A hydrate during the patch may have recorded the pre-patch row as stored.\n rows.forgetStored(scope, [replicaStorageKey(key, getSlot().entries[key]?.query)]);\n if (mapEntity(current, id, fn) === undefined) remove(key);\n else\n update(key, (data) => (data === undefined ? data : (mapEntity(data, id, fn) ?? data)), {\n persist: false,\n });\n }\n };\n\n /**\n * Confirmed patch of one entity everywhere it is loaded and in the persisted\n * rows of unloaded entries. `scope` targets a scope captured earlier (a\n * write confirmed after the account switched): when it is no longer active,\n * only that scope's persisted rows are patched and the view on screen —\n * another identity's — is left alone.\n */\n const updateEntity = <TItem>(\n id: string,\n fn: (item: TItem) => TItem | undefined,\n options?: { persist?: boolean; scope?: string },\n ) => {\n if (options?.scope !== undefined && options.scope !== resource.scope.get()) {\n const scope = options.scope;\n if (options.persist === false) return;\n const settle = () => reconcileLoaded(scope, id, fn);\n void patchStoredEntityRows(id, fn, scope).then(settle, settle);\n return;\n }\n void applyEntity(id, fn, options);\n };\n\n /**\n * Confirmed removal of one entity everywhere (see `updateEntity`, including\n * its captured `scope`). Unlike a plain mapper returning `undefined`, it is\n * also remembered for that scope:\n * a value hydrated afterwards — even by a read already in flight — comes\n * back without the entity (see `createEntityRemovalGuards`).\n */\n const removeEntity = (id: string, options?: { persist?: boolean; scope?: string }) => {\n const scope = options?.scope ?? resource.scope.get();\n // A removal confirmed after the account switched belongs to the scope that\n // asked for it: guard and patch that scope's rows, never the active view.\n const offScope = scope !== resource.scope.get();\n const release = entityGuards.guardEntity(scope, id);\n // A scope left behind has nothing on screen: only its persisted rows drop\n // the entity, and the guard keeps a later hydrate there from reading it back.\n const patch = offScope\n ? options?.persist === false\n ? undefined\n : patchStoredEntityRows(id, () => undefined, scope).then((patched) => {\n // Switched back meanwhile: drop it from anything hydrated since.\n reconcileLoaded(scope, id, () => undefined);\n return patched;\n })\n : applyEntity(id, () => undefined, options);\n // Without a storage patch (`persist: false`) only reads already in flight\n // can hold the entity; with one, reads that start before it lands can too.\n // A patch that did not land (untrusted scope, unreadable index or row, a\n // failed write, an identity switch) leaves the entity in an unloaded row:\n // every later hydrate of that row could resurrect it, so the guard is kept\n // — until a server value holds the entity again, or a later removal of the\n // same id lands its patch.\n if (patch)\n void patch.then(\n (patched) => {\n if (patched) release();\n },\n () => undefined,\n );\n else release();\n };\n\n const beginEntityOptimistic = <TItem>(\n id: string,\n fn: (item: TItem) => TItem | undefined,\n ): ReplicaOptimisticToken<TData>[] =>\n entityKeys(id).flatMap((key) => {\n // Removing a whole value (a detail) is applied on commit, not optimistically.\n if (!paging) {\n const current = port.read(key);\n if (current !== undefined && mapEntity(current, id, fn) === undefined) return [];\n }\n return [beginOptimistic(key, (data) => mapEntity(data, id, fn) ?? data)];\n });\n\n return {\n beginEntityOptimistic,\n entityKeys,\n forgetRestoredEntities,\n patchStoredEntity,\n removeEntity,\n updateEntity,\n withoutRemovedEntities,\n };\n};\n","import type {\n ReplicaEntryMeta,\n ReplicaPendingMutation,\n ReplicaSeedPatch,\n ReplicaSource,\n ReplicaState,\n} from './types';\n\n/**\n * Pure transition core of a replica. It never touches the store\n * or storage: it returns the next bookkeeping slot, the view writes the store\n * binding must apply, and the persistence effects it must run.\n *\n * The VIEW (what selectors read) lives in the domain store, wherever the\n * binding's lens puts it. The reducer only reads it through `readView`, so a\n * domain can keep its existing state shape (e.g. `topicDataMap`).\n */\nexport type ReplicaAction<T> =\n | {\n data: T;\n key: string;\n /**\n * Repaint a slot that answers a *different* query from the persisted page\n * (a navigation). Only the caller that knows the entry has moved on\n * (the requested query changed) may ask for it; by default a hydrate only\n * fills an empty slot.\n */\n overwrite?: boolean;\n params?: unknown;\n query?: string;\n scope: string;\n type: 'hydrate';\n updatedAt?: number;\n }\n | {\n /** Receives the confirmed value (base or view); `undefined` keeps it. */\n data: (confirmed: T | undefined) => T | undefined;\n key: string;\n params?: unknown;\n query?: string;\n scope: string;\n type: 'replace';\n }\n | {\n apply: (data: T | undefined) => T | undefined;\n key: string;\n persist: boolean;\n scope: string;\n /** Marks a provisional write (`'seed'`); defaults to the entry's own source. */\n source?: ReplicaSource;\n /**\n * Seed writes of one source (a list refresh, a session refresh). A later\n * seed write supersedes an earlier one of the same tag since the last\n * confirmed write, so a remembered seed history stays bounded.\n */\n seedTag?: string;\n type: 'update';\n }\n | {\n apply: (data: T) => T;\n id: number;\n key: string;\n /** Query the overlay is started under (see `ReplicaPendingMutation`). */\n query?: string;\n scope: string;\n type: 'optimistic';\n }\n | { confirm?: (data: T) => T; id: number; key: string; scope: string; type: 'commit' }\n | { id: number; key: string; scope: string; type: 'rollback' }\n | { key: string; scope: string; type: 'remove' }\n | { scope: string; type: 'resetScope' };\n\nexport type ReplicaEffect<T> =\n | { data: T; key: string; query?: string; scope: string; type: 'persist' }\n | { key: string; query?: string; scope: string; type: 'remove' };\n\nexport type ReplicaViewWrite<T> = { data: T | undefined; key: string } | { type: 'clear' };\n\nexport interface ReplicaTransition<T> {\n effects: ReplicaEffect<T>[];\n state: ReplicaState<T>;\n writes: ReplicaViewWrite<T>[];\n}\n\nexport const createReplicaState = <T>(): ReplicaState<T> => ({ entries: {} });\n\nconst materialize = <T>(\n base: T | undefined,\n pending: ReplicaPendingMutation<T>[],\n): T | undefined =>\n base === undefined\n ? undefined\n : pending.reduce<T>((data, mutation) => mutation.apply(data), base);\n\nconst noop = <T>(state: ReplicaState<T>): ReplicaTransition<T> => ({\n effects: [],\n state,\n writes: [],\n});\n\n/**\n * Drop the seed patches a new seed write of `tag` supersedes: those of the same\n * tag after the last confirmed patch. Repeated refreshes of one source then keep\n * one patch instead of one per refresh, while the order relative to confirmed\n * writes (and to other sources' seeds) is preserved.\n */\nconst coalesceSeedPatches = <T>(\n patches: ReplicaSeedPatch<T>[],\n isSeedWrite: boolean,\n tag: string | undefined,\n): ReplicaSeedPatch<T>[] => {\n if (!isSeedWrite) return patches;\n let lastConfirmed = -1;\n patches.forEach((patch, index) => {\n if (!patch.seed) lastConfirmed = index;\n });\n return patches.filter(\n (patch, index) => index <= lastConfirmed || !patch.seed || patch.tag !== tag,\n );\n};\n\nexport const replicaReducer = <T>(\n state: ReplicaState<T>,\n action: ReplicaAction<T>,\n readView: (key: string) => T | undefined,\n now: number = Date.now(),\n): ReplicaTransition<T> => {\n if (action.type === 'resetScope') {\n if (state.scope === action.scope) return noop(state);\n // A different identity owns memory now: drop every entry (and its view) of\n // the previous scope instead of letting it bleed into the new one.\n return {\n effects: [],\n state: { entries: {}, scope: action.scope },\n writes: state.scope === undefined ? [] : [{ type: 'clear' }],\n };\n }\n\n // Late results from another scope (workspace switch, logout) are ignored.\n if (state.scope !== undefined && state.scope !== action.scope) return noop(state);\n\n const scope = action.scope;\n const entry = state.entries[action.key];\n const view = readView(action.key);\n const confirmed = entry?.pending.length ? entry.base : view;\n const withEntry = (next: ReplicaEntryMeta<T> | undefined): ReplicaState<T> => {\n const entries = { ...state.entries };\n if (next) entries[action.key] = next;\n else delete entries[action.key];\n return { entries, scope };\n };\n\n switch (action.type) {\n case 'hydrate': {\n // A removed key never reaches here: the engine's removal tombstones drop a\n // storage read that resolves after a removal (see `hydrate` in engine.ts).\n // Hydrate only fills an empty slot: a server-confirmed value, an\n // optimistic write or any local write always wins over storage. A caller\n // that knows the slot answers a *different* query (a navigation) may ask\n // to repaint it from that query's persisted page instead — the overlays it\n // drops belong to the query being left. An overlay whose query is unknown\n // still wins: we cannot prove it is not this query's.\n //\n // A provisional `seed` is the other exception — it is a list row standing\n // in for a detail, not authoritative state, so the persisted value\n // replaces it. Otherwise a seeded entry would block the persisted detail\n // forever.\n const provisionalSeed = !!entry && entry.source === 'seed' && entry.pending.length === 0;\n if (entry && !provisionalSeed) {\n if (\n !action.overwrite ||\n entry.query === action.query ||\n entry.pending.some((mutation) => mutation.query === undefined)\n )\n return noop(state);\n } else if (!entry && view !== undefined) {\n return noop(state);\n }\n // The writes made over the seed are replayed onto the stored value, so\n // storage cannot clobber them: the seed's own (fresher) fields — a list\n // row's renamed title — and any confirmed edit made before storage\n // answered. Only a confirmed edit makes the result a local value (and\n // persists it); seed writes stay in-memory.\n const patches = (provisionalSeed && entry.seedPatches) || [];\n const data = patches.reduce((value, patch) => patch.apply(value) ?? value, action.data);\n const confirmedPatches = patches.filter((patch) => !patch.seed);\n return {\n effects: confirmedPatches.some((patch) => patch.persist)\n ? [{ data, key: action.key, query: action.query, scope, type: 'persist' }]\n : [],\n state: withEntry({\n params: action.params,\n pending: [],\n query: action.query,\n source: confirmedPatches.length ? 'local' : 'storage',\n updatedAt: confirmedPatches.length ? now : (action.updatedAt ?? now),\n }),\n writes: [{ data, key: action.key }],\n };\n }\n\n case 'replace': {\n // An overlay only describes the query it was started under, so a replace\n // for another query drops it instead of reapplying it: its base belongs to\n // the old query, and a later commit would insert that query's row here.\n const pending = (entry?.pending ?? []).filter(\n (mutation) => mutation.query === undefined || mutation.query === action.query,\n );\n // The merge basis under a query change is the old query's confirmed value\n // (never the view, which may still carry a dropped overlay).\n const basis = entry && entry.query !== action.query ? (entry.base ?? view) : confirmed;\n const next = action.data(basis) ?? basis;\n const query = 'query' in action ? action.query : entry?.query;\n const nextState = withEntry({\n base: pending.length ? next : undefined,\n params: action.params ?? entry?.params,\n pending,\n query,\n source: 'server',\n updatedAt: now,\n });\n if (next === undefined) return { effects: [], state: nextState, writes: [] };\n // In-flight optimistic mutations are rebased onto the fresh server value\n // so a background revalidation never flickers them away.\n const nextView = materialize(next, pending);\n return {\n effects: [{ data: next, key: action.key, query, scope, type: 'persist' }],\n state: nextState,\n writes: nextView === view ? [] : [{ data: nextView, key: action.key }],\n };\n }\n\n case 'update': {\n const nextView = action.apply(view);\n const pending = entry?.pending ?? [];\n const nextBase = pending.length ? action.apply(entry!.base) : nextView;\n if (nextView === view && nextBase === confirmed) return noop(state);\n // A provisional seed is never authoritative, so it must not persist: it\n // only stands in for a value another source owns, and persisting it would\n // overwrite that value's persisted row. A `seed` also only ever marks a\n // fresh slot — a value already in memory (written outside the binding) is\n // authoritative and is never downgraded to a seed.\n const source: ReplicaSource =\n entry?.source ?? (view === undefined ? (action.source ?? 'local') : 'local');\n const persist = action.persist && source !== 'seed';\n // Every write while the entry is a seed is remembered so a hydrate that\n // replaces the seed replays it (see `hydrate`): a confirmed write keeps\n // the seed provisional, and a seed write carries fresher fields.\n const isSeedWrite = action.source === 'seed';\n const seedPatches =\n source === 'seed'\n ? [\n ...coalesceSeedPatches(entry?.seedPatches ?? [], isSeedWrite, action.seedTag),\n {\n apply: action.apply,\n persist: !isSeedWrite && action.persist,\n ...(isSeedWrite && { seed: true, tag: action.seedTag }),\n },\n ]\n : entry?.seedPatches;\n return {\n effects:\n persist && nextBase !== undefined\n ? [{ data: nextBase, key: action.key, query: entry?.query, scope, type: 'persist' }]\n : [],\n state: withEntry({\n ...entry,\n base: pending.length ? nextBase : undefined,\n pending,\n seedPatches,\n source,\n updatedAt: now,\n }),\n writes: nextView === view ? [] : [{ data: nextView, key: action.key }],\n };\n }\n\n case 'optimistic': {\n if (view === undefined) return noop(state);\n const pending = [\n ...(entry?.pending ?? []),\n { apply: action.apply, id: action.id, query: action.query },\n ];\n return {\n effects: [],\n state: withEntry({\n ...entry,\n base: confirmed,\n pending,\n source: entry?.source ?? 'local',\n updatedAt: entry?.updatedAt ?? now,\n }),\n writes: [{ data: action.apply(view), key: action.key }],\n };\n }\n\n case 'commit':\n case 'rollback': {\n const mutation = entry?.pending.find((item) => item.id === action.id);\n if (!entry || !mutation) return noop(state);\n const pending = entry.pending.filter((item) => item.id !== action.id);\n const base =\n action.type === 'commit' && entry.base !== undefined\n ? (action.confirm ?? mutation.apply)(entry.base)\n : entry.base;\n // A plain commit confirms what the view already shows; only a rollback or\n // a server-provided `confirm` needs the view rebuilt from the base.\n const nextView =\n action.type === 'commit' && !action.confirm ? view : materialize(base, pending);\n return {\n effects:\n action.type === 'commit' && base !== undefined\n ? [{ data: base, key: action.key, query: entry.query, scope, type: 'persist' }]\n : [],\n state: withEntry({\n ...entry,\n base: pending.length ? base : undefined,\n pending,\n source: entry.source,\n updatedAt: action.type === 'commit' ? now : entry.updatedAt,\n }),\n writes: nextView === view ? [] : [{ data: nextView, key: action.key }],\n };\n }\n\n case 'remove': {\n return {\n effects: [{ key: action.key, query: entry?.query, scope, type: 'remove' }],\n state: withEntry(undefined),\n writes: view === undefined ? [] : [{ data: undefined, key: action.key }],\n };\n }\n }\n};\n","import isEqual from 'fast-deep-equal';\n\nimport {\n applyHeadPage,\n applyNextPage,\n collapseToHead,\n getNextPageCursor,\n insertHeadItems,\n joinPages,\n pagingFor,\n toPersistedPage,\n} from '../paging/operations';\nimport type { ReplicaPagedData, ReplicaPageResult, ReplicaPagingContext } from '../paging/types';\nimport { stableQueryKey } from '../resource/storageKey';\nimport type { ReplicaResource } from '../resource/types';\nimport type { ReplicaSource, ReplicaState } from '../state/types';\nimport type { ReplicaEngineOptions, ReplicaStorePort } from './types';\n\nexport interface ReplicaPaginationDeps<TParams, TData, TFetched> {\n fetcher?: (params: TParams, cursor?: any) => Promise<TFetched>;\n getSlot: () => ReplicaState<TData>;\n /** Keys with a `loadMore` request in flight (the only valid `isLoadingMore`). */\n loadingMore: Set<string>;\n options: Pick<ReplicaEngineOptions<TParams, TData, TFetched>, 'isClientOnly' | 'viewFields'>;\n port: ReplicaStorePort<TData>;\n resource: ReplicaResource<TParams, TData, TFetched>;\n update: (\n key: string,\n apply: (data: TData | undefined) => TData | undefined,\n options?: { persist?: boolean; seedTag?: string; source?: ReplicaSource },\n ) => boolean;\n}\n\n/**\n * The engine's paged-resource transitions: folding a head page into the loaded\n * pages, fetching the next page, head inserts and collapsing back to the head.\n * The pure page math lives in `paging/operations.ts`; this adds the entry,\n * scope and in-flight bookkeeping around it. Every method is a no-op (or a\n * pass-through) for a non-paged resource.\n */\nexport const createPagination = <TParams, TData, TFetched>({\n fetcher,\n getSlot,\n loadingMore,\n options,\n port,\n resource,\n update,\n}: ReplicaPaginationDeps<TParams, TData, TFetched>) => {\n const paging = resource.paging;\n const at = (key: string) => pagingFor(paging!, key);\n const pagingCtx: ReplicaPagingContext<any> = { isClientOnly: options.isClientOnly };\n\n /** The persistable part of a paged value (the value itself when not paged). */\n const toPersisted = (data: TData): TData =>\n paging ? (toPersistedPage(data as any, paging, pagingCtx) as TData) : data;\n\n /**\n * An overwrite hydrate repaints the entry from another query's persisted page.\n * Client-only rows (an in-flight upload / create) have no server row yet, so\n * that page cannot contain them — keep the ones still in the view, so a\n * same-pool query change (a re-sort, a view-mode switch) never drops them.\n * A cross-pool navigate is not \"client-only\" for the new params and is dropped.\n */\n const keepClientOnlyRows = (incoming: TData, current: TData | undefined, key: string): TData => {\n if (!paging || !options.isClientOnly || !current) return incoming;\n const page = incoming as unknown as ReplicaPagedData<unknown, unknown>;\n const currentItems = (current as unknown as ReplicaPagedData<unknown, unknown>).items ?? [];\n const incomingIds = new Set(page.items.map((item) => paging.getId(item)));\n const survivors = currentItems.filter(\n (item) => options.isClientOnly!(item) && !incomingIds.has(paging.getId(item)),\n );\n if (survivors.length === 0) return incoming;\n const items = joinPages(survivors, page.items, at(key).direction);\n return { ...(incoming as object), items } as TData;\n };\n\n const viewMatchesFields = (current: TData | undefined, params: TParams) => {\n const fields = options.viewFields?.(params);\n if (!current || !fields) return true;\n // Falsy descriptors (undefined / false / null) are equivalent.\n const norm = (value: unknown) => stableQueryKey(value || null);\n return Object.entries(fields).every(\n ([field, value]) => norm(value) === norm((current as Record<string, unknown>)[field]),\n );\n };\n\n const mergeHead = (\n key: string,\n incoming: TFetched,\n confirmed: TData | undefined,\n params: TParams,\n reset: boolean,\n ) => {\n const page = incoming as unknown as ReplicaPageResult<unknown, unknown>;\n const pageSize = (params as { pageSize?: number }).pageSize ?? page.items.length;\n const merged = {\n ...applyHeadPage(confirmed as any, page, { pageSize, reset }, at(key), pagingCtx),\n ...options.viewFields?.(params),\n isLoadingMore: loadingMore.has(key),\n };\n // Keep domain-only fields of the current view (e.g. transient flags).\n const next = { ...(confirmed as object), ...merged } as TData;\n return confirmed !== undefined && isEqual(next, confirmed) ? undefined : next;\n };\n\n /**\n * Fetch and merge the next page with the params of the loaded head page\n * (`fallbackParams` covers views seeded outside `useSync`). In `cursor` mode\n * paging only starts from a server-confirmed head page: a hydrated cursor\n * may be stale. A result is dropped when the scope, the query or the loaded\n * depth changed while it was in flight.\n */\n const loadMore = async (key: string, fallbackParams?: TParams): Promise<void> => {\n if (!paging || !fetcher) return;\n const entry = getSlot().entries[key];\n const current = port.read(key) as ReplicaPagedData<unknown, unknown> | undefined;\n if (!current || loadingMore.has(key)) return;\n if (paging.mode === 'cursor' && entry?.source === 'storage') return;\n const params = (entry?.params ?? fallbackParams) as TParams | undefined;\n if (params === undefined) return;\n const cursor = getNextPageCursor(current, at(key));\n if (cursor === null || cursor === undefined) return;\n\n const query = entry?.query;\n const scope = resource.scope.get();\n const depth = current.currentPage;\n const setLoading = (patch: object) =>\n update(key, (data) => data && ({ ...data, ...patch } as TData), { persist: false });\n\n loadingMore.add(key);\n setLoading({ isLoadingMore: true, loadMoreError: undefined });\n const isCurrent = () => {\n const latest = port.read(key) as ReplicaPagedData<unknown, unknown> | undefined;\n return (\n resource.scope.get() === scope &&\n getSlot().entries[key]?.query === query &&\n latest?.currentPage === depth\n );\n };\n try {\n const page = (await fetcher(params, cursor)) as unknown as ReplicaPageResult<\n unknown,\n unknown\n >;\n if (!isCurrent()) return void setLoading({ isLoadingMore: false });\n update(\n key,\n (data) => data && (applyNextPage(data as any, page, at(key), pagingCtx) as TData),\n { persist: (paging.persist?.pages ?? 1) > 1 },\n );\n } catch (error) {\n setLoading({ isLoadingMore: false, loadMoreError: isCurrent() ? error : undefined });\n } finally {\n loadingMore.delete(key);\n }\n };\n\n /** Insert rows at the head (new / streamed items). */\n const insertHead = <TItem>(key: string, items: TItem[], { persist = false } = {}) =>\n paging\n ? update(key, (data) => data && (insertHeadItems(data as any, items, at(key)) as TData), {\n persist,\n })\n : false;\n\n /** Drop loaded pages, keeping the head (e.g. after an edit inside older pages). */\n const collapse = (key: string) =>\n paging\n ? update(key, (data) => data && (collapseToHead(data as any, at(key)) as TData), {\n persist: false,\n })\n : false;\n\n return {\n collapse,\n insertHead,\n keepClientOnlyRows,\n loadMore,\n mergeHead,\n toPersisted,\n viewMatchesFields,\n };\n};\n","/**\n * How many removal tombstones one engine remembers. The guards exist to win a\n * race with a hydrate that started around a removal, so a modest window is\n * plenty; the cap is what keeps a long-lived session from growing forever.\n */\nexport const DEFAULT_REMOVAL_TOMBSTONE_LIMIT = 5000;\n\nexport interface ReplicaTombstones {\n /** Remember `scope`/`key` (idempotent). */\n add: (scope: string, key: string) => void;\n /** Forget `scope`/`key`; an emptied scope bucket is dropped too. */\n clear: (scope: string, key: string) => void;\n has: (scope: string, key: string) => boolean;\n /** Tracked key count (observability + tests). */\n size: () => number;\n}\n\n/**\n * Scope-keyed removal tombstones with a hard size bound.\n *\n * A removal must stay visible until a server value supersedes it — including\n * across a scope switch, so the keys are bucketed per scope rather than in one\n * flat set. But the engine lives as long as the page: a session that visits tens\n * of thousands of subjects (a task list full of items that simply have no\n * acceptance) would otherwise pin one entry per subject forever. So the oldest\n * keys are evicted once the cap is reached.\n *\n * Eviction is safe for what the tombstone is for: it closes a race with a\n * hydrate that was already in flight when the removal landed. By the time a key\n * is old enough to be evicted, any such read has long since settled.\n */\nexport const createTombstones = (limit = DEFAULT_REMOVAL_TOMBSTONE_LIMIT): ReplicaTombstones => {\n const byScope = new Map<string, Set<string>>();\n let tracked = 0;\n\n const evictOverflow = () => {\n while (tracked > limit) {\n // `Map`/`Set` iterate in insertion order, so the first entry is the oldest.\n const oldestScope = byScope.keys().next().value as string;\n const keys = byScope.get(oldestScope)!;\n keys.delete(keys.values().next().value as string);\n tracked -= 1;\n if (keys.size === 0) byScope.delete(oldestScope);\n }\n };\n\n return {\n add: (scope, key) => {\n const keys = byScope.get(scope) ?? new Set<string>();\n byScope.set(scope, keys);\n if (keys.has(key)) return;\n keys.add(key);\n tracked += 1;\n evictOverflow();\n },\n clear: (scope, key) => {\n const keys = byScope.get(scope);\n if (!keys?.delete(key)) return;\n tracked -= 1;\n if (keys.size === 0) byScope.delete(scope);\n },\n has: (scope, key) => byScope.get(scope)?.has(key) ?? false,\n size: () => tracked,\n };\n};\n","import { createTombstones, DEFAULT_REMOVAL_TOMBSTONE_LIMIT } from './tombstones';\n\n/**\n * Removal guard of one engine.\n *\n * An explicit removal (a deleted / unauthorized aggregate, or a subject whose\n * attachment is gone) drops the entry AND its persisted row — but a read of\n * that row that started before the removal still holds the old value, and a\n * removal leaves no trace in the slots for the `hydrate` guard to see. So a\n * scope+key is remembered as removed and refuses hydration until a server\n * value supersedes it, otherwise the late read resurrects the exact value the\n * removal just dropped.\n */\nexport const createRemovalGuards = () => {\n const removedEntries = createTombstones();\n /**\n * Keys whose persisted row delete was actually queued. `runEffects` refuses to\n * write while the scope is untrusted, so a removal made on a cold boot can arm\n * the guard without clearing the row. The guard alone must therefore not turn\n * a later removal into a no-op, or the stale row would survive and hydrate\n * again once the scope becomes trusted.\n */\n const purgedEntries = createTombstones();\n /**\n * Bumped on every removal of a scope+key. A network response whose request\n * started before the entry was removed (deleted, access revoked, pruned by an\n * authoritative parent list) must not `replace` it back: the slice records\n * the generation a request starts under and drops a response that crossed a\n * removal. Bounded like the tombstones; an evicted key reads 0, which only\n * ever drops a response (the next revalidate refetches), never admits one.\n */\n const removalGenerations = new Map<string, number>();\n const removalId = (scope: string, key: string) => `${scope}\\u0000${key}`;\n const removalGeneration = (scope: string, key: string) =>\n removalGenerations.get(removalId(scope, key)) ?? 0;\n const markRemoved = (scope: string, key: string) => {\n removedEntries.add(scope, key);\n const id = removalId(scope, key);\n const next = (removalGenerations.get(id) ?? 0) + 1;\n // Re-insert so the map's insertion order is least-recently-removed first.\n removalGenerations.delete(id);\n removalGenerations.set(id, next);\n if (removalGenerations.size > DEFAULT_REMOVAL_TOMBSTONE_LIMIT)\n removalGenerations.delete(removalGenerations.keys().next().value as string);\n };\n const clearRemoved = (scope: string, key: string) => {\n removedEntries.clear(scope, key);\n purgedEntries.clear(scope, key);\n };\n const isRemoved = (scope: string, key: string) => removedEntries.has(scope, key);\n const markPurged = (scope: string, key: string) => purgedEntries.add(scope, key);\n const isPurged = (scope: string, key: string) => purgedEntries.has(scope, key);\n\n return { clearRemoved, isPurged, isRemoved, markPurged, markRemoved, removalGeneration };\n};\n\nexport type ReplicaRemovalGuards = ReturnType<typeof createRemovalGuards>;\n\n/**\n * Entity removal guards of one engine.\n *\n * A hydrate that read its row before `removeEntity` patched storage still\n * holds the entity, so it is stripped from every value that hydrates while\n * such a read may be pending. A guard's lifetime follows the hydrates, not a\n * count: it is released once its storage patch landed (`releasedAt`) and is\n * dropped as soon as no hydrate that started before that point is pending.\n * So memory stays bounded by in-flight reads, and no guard a pending read\n * still needs is ever evicted. A patch that did not land is never released:\n * the unloaded row still holds the entity, so every later hydrate needs the\n * guard. A server value holding the entity again (restored) lifts it early.\n */\nexport const createEntityRemovalGuards = () => {\n /** Logical clock shared by hydrate starts and guard releases. */\n let guardClock = 0;\n /** Start ticks of the hydrates in flight, per scope. */\n const pendingHydrates = new Map<string, Set<number>>();\n /** Removed entity ids per scope; `releasedAt` is unset until the storage patch landed. */\n const removedEntities = new Map<string, Map<string, { releasedAt?: number }>>();\n const removedIds = (scope: string) => [...(removedEntities.get(scope)?.keys() ?? [])];\n\n /** Drop the guards no pending hydrate of `scope` can still need. */\n const pruneEntityGuards = (scope: string) => {\n const guards = removedEntities.get(scope);\n if (!guards) return;\n let oldestPending = Infinity;\n for (const start of pendingHydrates.get(scope) ?? [])\n oldestPending = Math.min(oldestPending, start);\n for (const [id, guard] of guards)\n if (guard.releasedAt !== undefined && guard.releasedAt <= oldestPending) guards.delete(id);\n if (guards.size === 0) removedEntities.delete(scope);\n };\n\n /**\n * Mark a hydrate of `scope` pending until settled: entity guards outlive every\n * read that may hold them. Returns the settle.\n */\n const startHydrate = (scope: string) => {\n const start = ++guardClock;\n const pending = pendingHydrates.get(scope) ?? new Set<number>();\n pendingHydrates.set(scope, pending);\n pending.add(start);\n return () => {\n pending.delete(start);\n if (pending.size === 0) pendingHydrates.delete(scope);\n pruneEntityGuards(scope);\n };\n };\n\n /** Arm the guard of entity `id` in `scope`. Returns its release (call once the patch landed). */\n const guardEntity = (scope: string, id: string) => {\n const guard: { releasedAt?: number } = {};\n const guards = removedEntities.get(scope) ?? new Map<string, { releasedAt?: number }>();\n removedEntities.set(scope, guards);\n guards.set(id, guard);\n return () => {\n // A newer removal of the same id owns the slot now.\n if (guards.get(id) !== guard) return;\n guard.releasedAt = ++guardClock;\n pruneEntityGuards(scope);\n };\n };\n\n /** Lift the guards of `ids` early (a server value holds them again). */\n const liftEntityGuards = (scope: string, ids: string[]) => {\n const guards = removedEntities.get(scope);\n if (!guards) return;\n for (const id of ids) guards.delete(id);\n if (guards.size === 0) removedEntities.delete(scope);\n };\n\n return { guardEntity, liftEntityGuards, removedIds, startHydrate };\n};\n\nexport type ReplicaEntityRemovalGuards = ReturnType<typeof createEntityRemovalGuards>;\n","import type { ReplicaPersistedRows } from '../persistence/persistedRows';\nimport type { ReplicaWriteQueue } from '../persistence/writeQueue';\nimport type { ReplicaResource } from '../resource/types';\nimport type { ReplicaStorePort } from './types';\n\nexport interface ReplicaScopeClearDeps<TData> {\n /** Devtools label prefix of host updates. */\n prefix: string;\n port: ReplicaStorePort<TData>;\n resource: ReplicaResource<any, TData, any>;\n rows: ReplicaPersistedRows<TData>;\n writeQueue: ReplicaWriteQueue<TData> | undefined;\n}\n\n/**\n * Resource-wide clear of one scope: memory, every persisted row and reads in\n * flight. A clear bumps the scope's generation so reads started before it are\n * dropped, and records its row purge so a later hydrate waits for it.\n */\nexport const createScopeClear = <TData>({\n port,\n prefix,\n resource,\n rows,\n writeQueue,\n}: ReplicaScopeClearDeps<TData>) => {\n const { deleteRows, readIndex } = rows;\n\n /** Bumped by every `clear()` of a scope; reads started before it are stale. */\n const clearGenerations = new Map<string, number>();\n const clearGeneration = (scope: string) => clearGenerations.get(scope) ?? 0;\n /**\n * The persisted-row purge of the last `clear()` per scope: `true` once every\n * row delete landed. A hydrate waits for it, and refuses to read while the\n * purge failed (an untrusted scope, a storage error) so a wiped resource can\n * never paint a row that survived it.\n */\n const scopePurges = new Map<string, Promise<boolean>>();\n const lastPurge = (scope: string) => scopePurges.get(scope);\n\n /**\n * Wipe the resource in the active scope: every entry leaves memory in one\n * host commit, every persisted row (all keys, all query variants) and the\n * index are deleted, and reads already in flight are dropped — a hydrate\n * started before the clear never dispatches, and `useSync` discards head\n * responses whose request started before it. Requests started afterwards\n * apply normally. Resolves `true` once the persisted rows are gone.\n */\n const clear = (): Promise<boolean> => {\n const scope = resource.scope.get();\n clearGenerations.set(scope, clearGeneration(scope) + 1);\n port.commit([{ type: 'clear' }], { entries: {}, scope }, `${prefix}/clear`);\n rows.forgetScope(scope);\n const purge = purgeScope(scope);\n scopePurges.set(scope, purge);\n return purge;\n };\n\n /**\n * `clear()` for any scope, including one that is not active (a user who\n * switched away while their data was being deleted): every persisted row of\n * `scope` and its index go, and for the active scope memory is wiped too\n * (exactly `clear()`). An inactive scope's memory is not on screen and is\n * left alone. The row deletes go through the write queue, so they land after\n * any write this session already queued for that scope — a row (or index\n * entry) written just before is purged rather than landing after the purge.\n * A later hydrate of `scope` waits for the purge. Resolves `true` once the\n * persisted rows are gone.\n */\n const clearScope = (scope: string): Promise<boolean> => {\n if (scope === resource.scope.get()) return clear();\n clearGenerations.set(scope, clearGeneration(scope) + 1);\n const purge = purgeScope(scope);\n scopePurges.set(scope, purge);\n return purge;\n };\n\n /** Delete every persisted row of `scope` (see `clear`). */\n const purgeScope = async (scope: string): Promise<boolean> => {\n if (!writeQueue) return true;\n // Until identity resolves the scope is a guess; never write into it.\n if (!resource.scope.canPersist()) return false;\n // Rows this session knows about are queued now, ahead of any later write.\n const queued = deleteRows(scope, [...(rows.indexedKeys(scope) ?? [])]);\n let persisted: string[];\n try {\n persisted = await readIndex(scope);\n } catch {\n return false;\n }\n // Keys this session tracks are already queued above, or were written by a\n // newer response since the clear (their row is fresh): skip both.\n const known = rows.indexedKeys(scope);\n const stale = persisted.filter((queryKey) => !known?.has(queryKey));\n const [first, rest] = await Promise.all([queued, deleteRows(scope, stale)]);\n return first && rest;\n };\n\n return { clear, clearGeneration, clearScope, lastPurge };\n};\n","import { createEntityPropagation } from '../entity/propagation';\nimport { createPersistedRows } from '../persistence/persistedRows';\nimport { ReplicaWriteQueue } from '../persistence/writeQueue';\nimport { replicaStorageKey } from '../resource/storageKey';\nimport type { ReplicaResource } from '../resource/types';\nimport {\n type ReplicaAction,\n type ReplicaEffect,\n replicaReducer,\n type ReplicaViewWrite,\n} from '../state/reducer';\nimport type { ReplicaSource, ReplicaState } from '../state/types';\nimport { createPagination } from './pagination';\nimport { createEntityRemovalGuards, createRemovalGuards } from './removalGuards';\nimport { createScopeClear } from './scopeClear';\nimport type {\n OptimisticMutationOptions,\n ReplicaEngineOptions,\n ReplicaHeadOutcome,\n ReplicaOptimisticToken,\n} from './types';\n\n/**\n * The replica engine: every transition of one resource, independent of any\n * UI framework or state library.\n *\n * It owns hydrate-if-empty, server replace, pagination, optimistic overlays\n * with commit/rollback, entity propagation, scope isolation and serialized\n * persistence. The host store keeps the rendered value (see\n * {@link ReplicaStorePort}); fetch scheduling (when to sync, dedupe, focus\n * revalidation) belongs to an adapter such as `local-replica/zustand`.\n */\nexport const createReplicaEngine = <TParams, TData, TFetched = TData>(\n resource: ReplicaResource<TParams, TData, TFetched>,\n options: ReplicaEngineOptions<TParams, TData, TFetched>,\n) => {\n const { port } = options;\n const paging = resource.paging;\n const prefix = options.actionPrefix ?? resource.name;\n const writeQueue = resource.storage ? new ReplicaWriteQueue<TData>(resource.storage) : undefined;\n const fetcher = options.fetcher ?? resource.fetcher;\n let mutationSeq = 0;\n /** Keys with a `loadMore` request in flight (the only valid `isLoadingMore`). */\n const loadingMore = new Set<string>();\n\n // ---- removal guards (see `removalGuards.ts`) -----------------------------\n const { clearRemoved, isPurged, isRemoved, markPurged, markRemoved, removalGeneration } =\n createRemovalGuards();\n const entityGuards = createEntityRemovalGuards();\n\n const getSlot = port.getState;\n const storageKey = (key: string, query?: string) => ({\n queryKey: replicaStorageKey(key, query),\n });\n\n const toPersisted = (data: TData): TData | null | undefined => {\n const paged = pagination.toPersisted(data);\n return options.toPersisted ? options.toPersisted(paged) : paged;\n };\n\n // ---- persisted rows (see `persistence/persistedRows.ts`) -----------------\n const rows = createPersistedRows<TData>({\n commit: (keys, state) =>\n port.commit(\n keys.map((key) => ({ data: undefined, key })),\n state,\n `${prefix}/evict`,\n ),\n getSlot,\n isRemoved,\n loadingMore,\n resource,\n writeQueue,\n });\n const { deleteRows, removeStoredVariants, retain, touchStorageKey } = rows;\n\n // ---- resource-wide clear (see `scopeClear.ts`) ---------------------------\n const { clear, clearGeneration, clearScope, lastPurge } = createScopeClear<TData>({\n port,\n prefix,\n resource,\n rows,\n writeQueue,\n });\n\n const runEffects = (effects: ReplicaEffect<TData>[]) => {\n if (!writeQueue || effects.length === 0) return;\n // Until identity resolves the scope is a guess; never write into it.\n if (!resource.scope.canPersist()) return;\n for (const effect of effects) {\n if (!resource.persistKey(effect.key)) continue;\n const key = { ...storageKey(effect.key, effect.query), scope: effect.scope };\n if (effect.type === 'remove') {\n // A repeated removal for this key can be a real no-op (see `remove`) —\n // but only once the row delete actually landed. A storage that rejects\n // the delete (a closed IndexedDB, a quota error) must leave the key\n // unpurged, so the next terminal answer retries it instead of letting a\n // stale row survive to hydrate again.\n // Every query variant goes: a row persisted under other filters would\n // otherwise hydrate the removed entry once the guard is superseded.\n void removeStoredVariants(effect.scope, effect.key, key.queryKey).then((removed) => {\n if (removed) markPurged(effect.scope, effect.key);\n });\n continue;\n }\n const data = toPersisted(effect.data);\n if (data === undefined) continue;\n if (data === null) {\n // Server-confirmed absence: remove the prior projection rather than\n // leaving it to be hydrated as if the value were still current.\n void deleteRows(effect.scope, [key.queryKey]);\n continue;\n }\n rows.writeRow(effect.scope, key.queryKey, data);\n }\n };\n\n /** Read an entry as it will be once `writes` are applied (latest write wins). */\n const readThrough = (writes: ReplicaViewWrite<TData>[], key: string): TData | undefined => {\n for (let i = writes.length - 1; i >= 0; i--) {\n const write = writes[i];\n if ('type' in write) return undefined;\n if (write.key === key) return write.data;\n }\n return port.read(key);\n };\n\n const dispatch = (action: ReplicaAction<TData>): boolean => runActions([action]);\n\n /**\n * Fold one or more actions into a single host commit. A caller that seeds\n * many keys (a list refresh) must not clone the view and notify subscribers\n * once per key; every action is still reduced in order, and the accumulated\n * writes are applied as ONE host update. A batch is dropped whole when any\n * action belongs to another identity (see {@link dispatch}).\n */\n function runActions(actions: ReplicaAction<TData>[]): boolean {\n if (actions.length === 0) return false;\n const activeScope = resource.scope.get();\n // An action captured under another identity is stale — drop it.\n if (actions.some((action) => action.scope !== activeScope)) return false;\n\n for (const action of actions) {\n // Every removal path (explicit `remove`, a missing response, an entity that\n // takes its whole value with it) arms the hydration guard for this key.\n if (action.type === 'remove') markRemoved(action.scope, action.key);\n // A replacement that reaches the active scope supersedes an earlier\n // removal, so the key may hydrate again. A response captured under another\n // scope is dropped above and must NOT clear its guard: the removal still\n // stands for its own scope, whose row delete may be pending or may have failed.\n if (action.type === 'replace') clearRemoved(action.scope, action.key);\n }\n\n const initial = getSlot();\n let slot = initial;\n const writes: ReplicaViewWrite<TData>[] = [];\n const effects: ReplicaEffect<TData>[] = [];\n const read = (key: string) => readThrough(writes, key);\n if (slot.scope !== undefined && slot.scope !== activeScope) {\n // Memory moves to another identity; what we knew of its rows can go.\n rows.forgetScope(slot.scope);\n const reset = replicaReducer(slot, { scope: activeScope, type: 'resetScope' }, read);\n writes.push(...reset.writes);\n slot = reset.state;\n }\n\n let changed = false;\n for (const action of actions) {\n const transition = replicaReducer(slot, action, read);\n writes.push(...transition.writes);\n effects.push(...transition.effects);\n // The reducer returns the entry's state unchanged for a no-op.\n if (transition.state !== slot) {\n slot = transition.state;\n changed = true;\n }\n }\n\n if (!changed && writes.length === 0 && slot === initial) return false;\n port.commit(writes, slot, `${prefix}/${actions.length > 1 ? 'batch' : actions[0].type}`);\n runEffects(effects);\n return true;\n }\n\n /**\n * Drop memory owned by another identity as soon as a new scope is active —\n * even when the new scope has nothing persisted and its fetch is slow, the\n * previous user's / workspace's rows must not stay on screen.\n */\n const ensureScope = (scope: string) => {\n if (scope === resource.scope.get() && getSlot().scope !== scope)\n dispatch({ scope, type: 'resetScope' });\n };\n\n const getConfirmed = (key: string): TData | undefined => {\n const entry = getSlot().entries[key];\n return entry?.pending.length ? entry.base : port.read(key);\n };\n\n const hydrate = async (\n params: TParams,\n scope = resource.scope.get(),\n { overwrite = false }: { overwrite?: boolean } = {},\n ) => {\n if (!resource.storage) return false;\n // An identity-less runtime reads network-only: its scope is a guess, so\n // hydrating it could paint another session's private rows.\n if (resource.scope.canHydrate && !resource.scope.canHydrate()) return false;\n const key = resource.key(params);\n if (!resource.persistKey(key)) return false;\n // A removed entry is not read back: only a later server value supersedes\n // the removal (see `replace`), so a stale row can never repaint it.\n if (isRemoved(scope, key)) return false;\n // Pending until settled: entity guards outlive every read that may hold them.\n const settle = entityGuards.startHydrate(scope);\n try {\n return await readAndHydrate(params, key, scope, overwrite);\n } finally {\n settle();\n }\n };\n\n const readAndHydrate = async (\n params: TParams,\n key: string,\n scope: string,\n overwrite: boolean,\n ) => {\n const storage = resource.storage!;\n // A read started before a `clear()` of this scope holds a wiped row.\n const generation = clearGeneration(scope);\n // After a `clear()`, read only once its row deletes landed.\n const purge = lastPurge(scope);\n if (purge && !(await purge)) return false;\n const query = resource.query(params);\n const { queryKey } = storageKey(key, query);\n const writesBefore = rows.writeCount();\n const cached = await storage.get({ queryKey, scope });\n if (!cached) return false;\n // Re-check after the read: a removal or a clear that landed while it was in\n // flight must not resurrect the row it just dropped.\n if (isRemoved(scope, key) || clearGeneration(scope) !== generation) return false;\n // The row holds what was read, unless a write was queued while reading.\n rows.rememberRead(scope, queryKey, cached.data, writesBefore);\n if (options.isHydratable && !options.isHydratable(cached.data, params)) return false;\n // Entities deleted while the read was in flight may still be in the row.\n const stored = withoutRemovedEntities(scope, cached.data);\n if (stored === undefined) return false;\n const data = overwrite ? pagination.keepClientOnlyRows(stored, port.read(key), key) : stored;\n const applied = dispatch({\n data,\n key,\n overwrite,\n params,\n query,\n scope,\n type: 'hydrate',\n updatedAt: cached.updatedAt,\n });\n // A hydrated row is a used row (bounded resources keep LRU order).\n if (applied && resource.scope.canPersist()) touchStorageKey(scope, queryKey);\n return applied;\n };\n\n /** Non-paged: whether a (prepared) head response is a terminal absence (`isMissing`). */\n const isMissingHead = (incoming: TFetched): boolean => !paging && !!options.isMissing?.(incoming);\n\n /**\n * Fold a head response in and report what it was: dropped by `prepareHead`,\n * a terminal absence (`isMissing`, applied as a removal) or a replacement.\n * `changed` is whether the store moved. `replace` is the boolean shorthand;\n * the zustand slice's settle pipeline reads the outcome to pick its effects.\n */\n const applyHead = (\n params: TParams,\n fetched: TFetched,\n scope = resource.scope.get(),\n ): { changed: boolean; outcome: ReplicaHeadOutcome } => {\n const key = resource.key(params);\n const incoming = options.prepareHead\n ? options.prepareHead(fetched, port.read(key), params)\n : fetched;\n if (incoming === undefined) return { changed: false, outcome: 'dropped' };\n // A response that says the entry is gone clears it outright: the merge path\n // would keep — and re-persist — the confirmed value it is replacing. It also\n // arms the hydration guard, so a persisted read still in flight cannot bring\n // the dropped value back.\n if (isMissingHead(incoming)) {\n // Route through `remove` so a repeated \"missing\" is a no-op and a response\n // captured under another scope is dropped rather than applied here.\n return { changed: remove(key, scope), outcome: 'missing' };\n }\n const query = resource.query(params);\n const entry = getSlot().entries[key];\n // A different query (filters, sort) must not merge with loaded pages. A\n // view seeded without bookkeeping is compared by its `viewFields`.\n const reset = entry\n ? entry.query !== query\n : paging !== undefined && !pagination.viewMatchesFields(port.read(key), params);\n const applied = dispatch({\n data: (confirmed) =>\n paging\n ? pagination.mergeHead(key, incoming, confirmed, params, reset)\n : options.merge\n ? options.merge(incoming, confirmed, params)\n : (incoming as unknown as TData),\n key,\n params,\n query,\n scope,\n type: 'replace',\n });\n if (applied) forgetRestoredEntities(scope, getConfirmed(key));\n return { changed: applied, outcome: 'replaced' };\n };\n\n const replace = (params: TParams, fetched: TFetched, scope = resource.scope.get()) =>\n applyHead(params, fetched, scope).changed;\n\n /**\n * Confirmed local write: patches the view (and the base under any overlay).\n * Pass `source: 'seed'` for a provisional row (a list row standing in for a\n * detail): it is hydratable and never persisted, so the authoritative value it\n * stands in for is preserved (see `ReplicaSource`).\n */\n const update = (\n key: string,\n apply: (data: TData | undefined) => TData | undefined,\n {\n persist = true,\n seedTag,\n source,\n }: { persist?: boolean; seedTag?: string; source?: ReplicaSource } = {},\n ) =>\n dispatch({ apply, key, persist, scope: resource.scope.get(), seedTag, source, type: 'update' });\n\n /**\n * Confirmed local write to several keys as ONE host update — same per-key\n * semantics as {@link update}, but a whole list seeds in a single commit\n * instead of one per row (no repeated view cloning or subscriber churn).\n */\n const updateMany = (\n entries: { apply: (data: TData | undefined) => TData | undefined; key: string }[],\n {\n persist = true,\n seedTag,\n source,\n }: { persist?: boolean; seedTag?: string; source?: ReplicaSource } = {},\n ) => {\n const scope = resource.scope.get();\n return runActions(\n entries.map(({ apply, key }) => ({\n apply,\n key,\n persist,\n scope,\n seedTag,\n source,\n type: 'update' as const,\n })),\n );\n };\n\n /**\n * Purge a removal that belongs to a scope which is no longer active.\n *\n * The in-memory view is not ours to touch — the active scope owns it — but the\n * guard and the persisted row both belong to THAT scope. Arming the one and\n * deleting the other keeps a switch back from hydrating a value the server\n * just deleted or denied. `dispatch` would reject the off-scope action\n * outright (see `replace`'s stale-scope guard), so the row would otherwise\n * survive untouched.\n *\n * Like `remove`, the delete only counts as done once it was actually queued:\n * an untrusted scope refuses writes, so the guard stays armed as `unpurged`\n * and a later removal retries instead of reporting a no-op that never deletes.\n */\n const purge = (key: string, scope: string): boolean => {\n if (isRemoved(scope, key) && isPurged(scope, key)) return false;\n markRemoved(scope, key);\n // Nothing persisted (no storage, or a key this resource never persists) is\n // already \"cleared\": the guard alone is the whole purge.\n if (!writeQueue || !resource.persistKey(key)) {\n markPurged(scope, key);\n return false;\n }\n if (!resource.scope.canPersist()) return false;\n void removeStoredVariants(scope, key, storageKey(key).queryKey).then((removed) => {\n if (removed) markPurged(scope, key);\n });\n return true;\n };\n\n /**\n * Drop an entry and its persisted row.\n *\n * A removal is a no-op only once there is genuinely nothing left to do: the\n * key is guarded, its value is gone, AND its stale row was already scheduled\n * for deletion (or there is no persisted row to clear). A subject with no\n * acceptance polls `null` every couple of seconds, and re-emitting the same\n * delete on every tick would only churn storage. But a removal whose delete\n * was skipped — an untrusted scope refuses writes — keeps retrying, so the row\n * cannot survive to hydrate again once the scope is trusted.\n *\n * A removal captured under another identity (a late NOT_FOUND arriving after a\n * workspace switch) is routed to {@link purge}: it must not touch the scope on\n * screen, yet its own scope's row still has to go.\n */\n const remove = (key: string, scope: string = resource.scope.get()): boolean => {\n if (scope !== resource.scope.get()) return purge(key, scope);\n // Nothing persisted (no storage, or a key this resource never persists) is\n // already \"cleared\"; otherwise the row delete must have been queued.\n const rowCleared = !writeQueue || !resource.persistKey(key) || isPurged(scope, key);\n if (rowCleared && isRemoved(scope, key) && port.read(key) === undefined) return false;\n return dispatch({ key, scope, type: 'remove' });\n };\n\n /**\n * Persist the confirmed value of an entry as it is now — the flush after a\n * burst of in-memory `update(..., { persist: false })` writes (a stream).\n */\n const persist = (key: string) => {\n const scope = resource.scope.get();\n if (getSlot().scope !== undefined && getSlot().scope !== scope) return;\n const data = getConfirmed(key);\n if (data === undefined) return;\n runEffects([{ data, key, query: getSlot().entries[key]?.query, scope, type: 'persist' }]);\n };\n\n const revalidate = (key?: string): Promise<unknown> =>\n options.revalidate ? options.revalidate(key) : Promise.resolve();\n\n /**\n * Start an optimistic overlay now and settle it later (multi-resource flows).\n * `query` tags the overlay with the query it describes; a caller that knows\n * the requested query (e.g. before the first page painted) should pass it, so\n * the overlay is scoped to that query rather than kept across every change.\n */\n const beginOptimistic = (\n key: string,\n apply: (data: TData) => TData,\n query?: string,\n ): ReplicaOptimisticToken<TData> => {\n const scope = resource.scope.get();\n const id = ++mutationSeq;\n // Tag the overlay with the query it describes: the entry may move on to\n // another query (or another query may reuse the key) before it settles.\n dispatch({\n apply,\n id,\n key,\n query: query ?? getSlot().entries[key]?.query,\n scope,\n type: 'optimistic',\n });\n return {\n commit: (confirm) => {\n dispatch({ confirm, id, key, scope, type: 'commit' });\n },\n rollback: () => {\n dispatch({ id, key, scope, type: 'rollback' });\n },\n };\n };\n\n /**\n * Apply `apply` to the view right away, run `serverCall`, then commit (the\n * confirmed value is persisted) or roll back (the view is rebuilt from the\n * confirmed base plus any other in-flight overlays) and rethrow.\n */\n const optimistic = async <TResult>(\n key: string,\n apply: (data: TData) => TData,\n serverCall: () => Promise<TResult>,\n mutationOptions: OptimisticMutationOptions<TData, TResult> = {},\n ): Promise<TResult> => {\n const token = beginOptimistic(key, apply);\n try {\n const result = await serverCall();\n token.commit(mutationOptions.confirm?.(result));\n return result;\n } catch (error) {\n token.rollback();\n throw error;\n } finally {\n if (mutationOptions.revalidate) void revalidate(key);\n }\n };\n\n // ---- pagination (see `pagination.ts`) -----------------------------------\n const pagination = createPagination<TParams, TData, TFetched>({\n fetcher,\n getSlot,\n loadingMore,\n options,\n port,\n resource,\n update,\n });\n const { collapse, insertHead, loadMore } = pagination;\n\n // ---- entity propagation (see `entity/propagation.ts`) --------------------\n const entities = createEntityPropagation<TData>({\n beginOptimistic,\n entity: options.entity,\n entityGuards,\n getSlot,\n paging,\n port,\n remove,\n resource,\n rows,\n update,\n });\n const {\n beginEntityOptimistic,\n entityKeys,\n forgetRestoredEntities,\n patchStoredEntity,\n removeEntity,\n updateEntity,\n withoutRemovedEntities,\n } = entities;\n const { patchStoredRows } = rows;\n\n return {\n applyHead,\n beginEntityOptimistic,\n beginOptimistic,\n clear,\n clearGeneration,\n clearScope,\n removalGeneration,\n collapse,\n dispatch,\n ensureScope,\n entityKeys,\n fetcher,\n getConfirmed,\n hydrate,\n insertHead,\n isMissingHead,\n loadMore,\n optimistic,\n patchStoredEntity,\n patchStoredRows,\n persist,\n remove,\n removeEntity,\n replace,\n resource,\n retain,\n revalidate,\n update,\n updateEntity,\n updateMany,\n };\n};\n\nexport type ReplicaEngine<TParams, TData, TFetched = TData> = ReturnType<\n typeof createReplicaEngine<TParams, TData, TFetched>\n>;\n"],"mappings":"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,CAAC,MACzC;EACrB,MAAM,QAAQ,gBAAgB,KAAK,KAAK;EACxC,IAAI;GACF,MAAM,SAAS,MAAM,WAAW;GAChC,MAAM,OAAO,gBAAgB,UAAU,MAAM,CAAC;GAC9C,OAAO;EACT,SAAS,OAAO;GACd,MAAM,SAAS;GACf,MAAM;EACR,UAAU;GACR,IAAI,gBAAgB,YAAY,WAAgB,GAAG;EACrD;CACF;CAGA,MAAM,aAAa,iBAA2C;EAC5D;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,EAAE,UAAU,YAAY,aAAa;CAe3C,MAAM,EACJ,uBACA,YACA,wBACA,mBACA,cACA,cACA,2BAnBe,wBAA+B;EAC9C;EACA,QAAQ,QAAQ;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CASW;CACX,MAAM,EAAE,oBAAoB;CAE5B,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
|