For AI agents (Claude Code, Copilot, Cursor): read AGENTS.md and packages/store/AGENTS.md before writing code. This issue is a complete spec. Follow it exactly.
Objective
Add an optional equalityFn argument to the store selector hook. When the new selected slice is equal to the old one under equalityFn, skip the re-render. Ship a shallow comparator.
Package scope
packages/store. All work is confined here. Import shared types from @termuijs/core.
Files to create or modify
CREATE: packages/store/src/shallow.ts
CREATE: packages/store/src/shallow.test.ts
MODIFY: packages/store/src/store.ts (accept equalityFn in the hook, gate setState on it)
MODIFY: packages/store/src/index.ts (add the shallow export)
API contract
export type EqualityFn<U> = (a: U, b: U) => boolean;
export function shallow<U>(a: U, b: U): boolean;
export interface UseStore<T> {
(): T;
<U>(selector: Selector<T, U>, equalityFn?: EqualityFn<U>): U;
getState: GetState<T>;
setState: SetState<T>;
subscribe(listener: Listener<T>): () => void;
destroy(): void;
computed<U>(selector: Selector<T, U>): Computed<U>;
}
Acceptance criteria
Test expectations
File: packages/store/src/shallow.test.ts
Run: bun vitest run packages/store
Named cases:
shallow returns true for equal flat objects
shallow returns false when a value differs
shallow returns false when key sets differ
selector with shallow skips notify on equal slice
selector with shallow notifies on changed slice
Use the real store from createStore. Use vi.fn() as the subscribe listener to count notifications. Never mutate shared module state.
Reference pattern to follow
Follow packages/store/src/store.ts, match the useStore hook shape, the useRef pattern already used for selectorRef, and the comment style.
Not included
- Deep equality
- Per-store default comparators
- Memoized selector factories
- Any change to
computed
Do not touch
- Any package other than
packages/store
packages/core (import shared types, do not modify them)
bun.lock
.github/
Agent prompt (copy this into your AI agent)
Read AGENTS.md at the repo root and packages/store/AGENTS.md.
Read the reference file packages/store/src/store.ts and copy its structure.
Task: add an optional equalityFn to the selector hook and ship a shallow comparator, exactly to the API contract in this issue.
Plan first. Create the files. Export shallow from packages/store/src/index.ts.
Confine all work to packages/store. Do not edit bun.lock. Do not add dependencies.
When done run: bun vitest run packages/store && bun run typecheck. Both must pass.
Before you open the PR
GSSoC 2026
This is an intermediate-level issue. Comment "I would like to work on this" to get assigned. You have 7 days to open a PR after assignment.
Objective
Add an optional
equalityFnargument to the store selector hook. When the new selected slice is equal to the old one underequalityFn, skip the re-render. Ship ashallowcomparator.Package scope
packages/store. All work is confined here. Import shared types from@termuijs/core.Files to create or modify
API contract
Acceptance criteria
useStore(selector)keepsObject.isbehavior when noequalityFnis passeduseStore(selector, shallow)does not re-render when a new slice is shallow-equal to the previoususeStore(selector, shallow)re-renders when a shallow-compared key changesequalityFnis honored instead of the defaultshallowreturnstruefor objects with the same keys andObject.isvalues,falseotherwiseequalityFnis read through a ref so a changed function does not leak stale comparisonsbun vitest run packages/storepassesbun run typecheckpassesTest expectations
Named cases:
shallow returns true for equal flat objectsshallow returns false when a value differsshallow returns false when key sets differselector with shallow skips notify on equal sliceselector with shallow notifies on changed sliceUse the real store from
createStore. Usevi.fn()as the subscribe listener to count notifications. Never mutate shared module state.Reference pattern to follow
Follow
packages/store/src/store.ts, match theuseStorehook shape, theuseRefpattern already used forselectorRef, and the comment style.Not included
computedDo not touch
packages/storepackages/core(import shared types, do not modify them)bun.lock.github/Agent prompt (copy this into your AI agent)
Before you open the PR
bun run build && bun vitest run && bun run typecheckand all passpackages/storebun.lockhas no unrelated changesGSSoC 2026
This is an intermediate-level issue. Comment "I would like to work on this" to get assigned. You have 7 days to open a PR after assignment.