Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
3223df7
Use newest Onyx changes
fabioh8010 Apr 16, 2026
7c53b58
Merge branch '@chrispader/bump-onyx-to-3.0.46' into feature/onyxutils…
fabioh8010 Apr 21, 2026
d4052e2
Use newest Onyx changes
fabioh8010 Apr 21, 2026
450c868
Fix usage of OnyxUtils.get
fabioh8010 Apr 21, 2026
4e40a58
Merge branch 'main' into feature/onyxutils-get-synchronous-2
fabioh8010 Jul 22, 2026
eae5a28
Merge branch 'main' of github.com:Expensify/App into feature/onyxutil…
LukasMod Jul 29, 2026
8c7876f
Merge branch 'main' of github.com:Expensify/App into feature/onyxutil…
LukasMod Jul 29, 2026
511a0f1
Merge branch 'main' of github.com:Expensify/App into feature/onyxutil…
LukasMod Aug 3, 2026
f556ef8
Merge branch 'main' into feature/onyxutils-get-synchronous-2
fabioh8010 Aug 4, 2026
c9d9e27
Merge remote-tracking branch 'origin/main' into feature/onyxutils-get…
fabioh8010 Aug 4, 2026
e39dfac
Update patch file
fabioh8010 Aug 4, 2026
4b90db1
Merge branch 'main' of github.com:Expensify/App into feature/onyxutil…
LukasMod Aug 5, 2026
e7d723f
update patch
LukasMod Aug 5, 2026
8636510
Merge branch 'main' into feature/onyxutils-get-synchronous-2
fabioh8010 Aug 6, 2026
b56b537
Update patch file
fabioh8010 Aug 6, 2026
212dea3
Merge remote-tracking branch 'refs/remotes/fork-ck/feature/onyxutils-…
fabioh8010 Aug 6, 2026
fe03665
Merge branch 'main' into feature/onyxutils-get-synchronous-2
fabioh8010 Aug 7, 2026
2ad249f
Merge branch 'main' of github.com:Expensify/App into feature/onyxutil…
LukasMod Aug 12, 2026
6b07fdb
Add render-position lint rule and caller-graph checker for synchronou…
LukasMod Aug 13, 2026
1da41bb
Add Onyx synchronous read semantics test suites
LukasMod Aug 13, 2026
2d59353
Merge branch 'main' of github.com:Expensify/App into feature/onyxutil…
LukasMod Aug 17, 2026
35951b0
replace patch with commit link
LukasMod Aug 17, 2026
bc23444
update gh commit link
LukasMod Aug 17, 2026
475ad7e
fix knip, spellcheck, unit tests
LukasMod Aug 17, 2026
a3d8540
update addUtilsToWindow
LukasMod Aug 17, 2026
c9d24c1
Read Onyx through the public get instead of the OnyxUtils deep import…
LukasMod Aug 17, 2026
b1db155
Read tsconfig paths through TypeScript so the reachability checker su…
LukasMod Aug 17, 2026
6e1c752
Test that a synchronous read misses storage-backed data before Onyx h…
LukasMod Aug 17, 2026
569e00f
fix onyx derived init
LukasMod Aug 17, 2026
e7f0876
Merge remote-tracking branch 'upstream/main' into feature/onyxutils-g…
LukasMod Aug 18, 2026
140e4f0
Restore hydration-safe GPS draft read dropped by the main merge
LukasMod Aug 18, 2026
5295689
Merge branch 'main' of github.com:Expensify/App into feature/onyxutil…
LukasMod Aug 18, 2026
9d07fea
add 2 more onyx get eslint rules
LukasMod Aug 17, 2026
3a07db5
Merge the three Onyx read rules into no-unsafe-onyx-read
LukasMod Aug 19, 2026
8ec1d11
Point the Onyx bypass runner and graph scripts at the merged rule
LukasMod Aug 19, 2026
dad3090
Merge branch 'main' of github.com:Expensify/App into feature/onyxutil…
LukasMod Aug 19, 2026
202188b
Tighten comments across the Onyx read tooling
LukasMod Aug 19, 2026
b2f8a3c
Report unproven render-reachability verdicts and run the check from lint
LukasMod Aug 19, 2026
5bf4b4b
treat an untraceable caller chain as unproven in the render reachabil…
LukasMod Aug 19, 2026
3ce6c37
replace script checkRenderReachability with AI skills
LukasMod Aug 19, 2026
e8e2724
update get skill
LukasMod Aug 19, 2026
8201ad2
add trackOnyxGetMigration
LukasMod Aug 19, 2026
3230284
update skills, remove checkOnyxConnectBypass
LukasMod Aug 19, 2026
16c253e
Untrack the Onyx get validation plan and restore checkOnyxConnectBypass
LukasMod Aug 19, 2026
b037b74
fix fmt and spellcheck
LukasMod Aug 19, 2026
c7b4f2d
update rule with awaiting body
LukasMod Aug 19, 2026
93d8f95
update ONYX-DATA-MANAGEMENT
LukasMod Aug 19, 2026
62d6332
scripts for analysis
fabioh8010 Aug 18, 2026
5f58eb9
Match the onyx counters anchor to both keyChanged signatures
LukasMod Aug 18, 2026
757b38b
Correct the A4 test comment that credited the patch for derived-key f…
LukasMod Aug 17, 2026
d83c5a0
Read Onyx through the public get in useUpdateGpsTripOnReconnect and c…
LukasMod Aug 19, 2026
f44f961
update ONYX-1
LukasMod Aug 20, 2026
3adabea
remove old analytics
LukasMod Aug 20, 2026
3dbc451
update AI rules and script
LukasMod Aug 20, 2026
86127ce
update Onyx rules with F
LukasMod Aug 20, 2026
557c1fa
Merge branch 'main' of github.com:Expensify/App into feature/onyxutil…
LukasMod Aug 21, 2026
66897f4
clean up trackOnyxGetMigration
LukasMod Aug 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .claude/skills/coding-standards/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Coding standards for the Expensify App. Each standard is a standalone file in `r
| Consistency | `CONSISTENCY-*` | Platform checks, magic values, unused props, ESLint discipline, localization, file naming, JSDoc |
| Clean React Patterns | `CLEAN-REACT-PATTERNS-*` | Composition, component ownership, state structure, prop typing, function components |
| UI | `UI-*` | Loading indicators, scrollable pages, styling conventions |
| Onyx | `ONYX-*` | Reading Onyx data outside render, and off a tick that wrote |

## Quick Reference

Expand Down Expand Up @@ -74,6 +75,9 @@ Coding standards for the Expensify App. Each standard is a standalone file in `r
- [UI-2](rules/ui-2-new-page-scrollview.md) — New pages must be scrollable
- [UI-3](rules/ui-3-no-inline-styles.md) — Do not use inline style objects

### Onyx
- [ONYX-1](rules/onyx-1-no-render-reachable-onyx-read.md) — Keep synchronous Onyx reads off the render path and out of a written tick

## Usage

**During development**: When writing or modifying `src/` files, consult the relevant standard files for detailed conditions, examples, and exceptions.
Expand Down

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions .claude/skills/onyx-get/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
name: onyx-get
description: Onyx.get() reads the Onyx cache synchronously and never subscribes. Use when writing or reviewing an Onyx read outside render, when a component or hook gains a call into a library function, or when converting a function off forwarded Onyx parameters or module-level caches.
---

`Onyx.get(key)` returns what is in the cache right now and never subscribes, so it belongs only in code that runs on an event: action creators, libraries, network handlers, and callbacks such as `useCallback`, `useEffect` and event handlers. Before reaching for it, prefer a pure function that takes the data as a parameter. `Onyx.get()` is the answer when threading the value through every caller is the only thing that parameter buys.

**The rules are in [ONYX-DATA-MANAGEMENT.md](../../../contributingGuides/philosophies/ONYX-DATA-MANAGEMENT.md#reading-onyx-data-useonyx-onyxget-and-onyxconnectwithoutview).** Read that section before writing or converting a read. Every rule there has to hold at the call site.

`npm run lint-changed` runs `no-unsafe-onyx-read`, which checks three of them: not during render, not at module scope, and not after an un-awaited write in the same body. A clean run is not a verdict on the rest.

The rest are in `ONYX-1` (`.claude/skills/coding-standards/rules/onyx-1-no-render-reachable-onyx-read.md`), which carries the caller sweep and the two shapes lint structurally cannot see: a read reached from render through a caller, and a write in the caller with the read one call away. Apply it when writing the read, not only when reviewing it.
7 changes: 4 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,13 @@ Major action categories:
- `Search.ts`: Search operations
- `Travel.ts`: Travel features

### Reading Onyx data (`useOnyx` vs `Onyx.connectWithoutView`)
There are only two ways to read Onyx data:
### Reading Onyx data (`useOnyx`, `Onyx.get()`, `Onyx.connectWithoutView`)
There are three ways to read Onyx data:
1. **`useOnyx`** (`@hooks/useOnyx`) — the default for anything a component renders.
2. **`Onyx.connectWithoutView`** — only for non-render logic (module-level state in actions/libraries) that genuinely can't use `useOnyx`.
3. **`Onyx.get()`**: a synchronous, non-subscribing read of the cache, for non-render code that needs a value when it runs. Never during render, never at module scope, and never after an un-awaited write to the same key in that tick.

Before either, prefer a **pure function** that receives the data as parameters: it does not read Onyx itself — the caller reads (with `useOnyx` or `Onyx.connectWithoutView`) and passes the data in. Do not add a new `Onyx.connectWithoutView` by copying existing usage — justify each one on its own with a comment explaining why it is needed. Using it in a component for performance requires `@frontend-performance` approval on Slack (link it in the PR description). See [Onyx Data Management](contributingGuides/philosophies/ONYX-DATA-MANAGEMENT.md#reading-onyx-data-useonyx-vs-onyxconnectwithoutview).
Before any of them, prefer a **pure function** that receives the data as parameters: it does not read Onyx itself — the caller reads and passes the data in. Do not add a new `Onyx.connectWithoutView` by copying existing usage — justify each one on its own with a comment explaining why it is needed. Using it in a component for performance requires `@frontend-performance` approval on Slack (link it in the PR description). The full rules for all three, including the conditions a read must meet before it moves into the function that uses it, are in [Onyx Data Management](contributingGuides/philosophies/ONYX-DATA-MANAGEMENT.md#reading-onyx-data-useonyx-onyxget-and-onyxconnectwithoutview).

## Build & Deployment

Expand Down
4 changes: 4 additions & 0 deletions config/eslint/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@ const config = defineConfig([
'rulesdir/require-live-region-for-status-updates': 'error',
'rulesdir/require-a11y-disable-justification': 'error',
'rulesdir/no-direct-pre-insert-fullscreen-under-rhp': 'error',
// Position and order for the synchronous Onyx read: not during render, where the read does not subscribe; not at module
// scope, where it runs at import time, before Onyx.init() has hydrated the cache; and not after an un-awaited write in
// the same body, where Onyx.merge() and Onyx.update() apply in a later microtask so the read returns the pre-write value.
'rulesdir/no-unsafe-onyx-read': 'error',
'rulesdir/require-locale-for-localized-date-format': 'error',
'rulesdir/prefer-narrow-hook-dependencies': [
'error',
Expand Down
2 changes: 1 addition & 1 deletion contributingGuides/philosophies/DATA-BINDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function getReportName(reportID: string): string {
### - Library files that are not connected or associated to any UI SHOULD use `Onyx.connectWithoutView()` to subscribe to changes in Onyx data
Library files are located in `/src/lib` but excluding the actions in `/src/lib/actions` which have their own rule above.

`useOnyx()` is the standard for accessing Onyx data for React components. Non-React library files should always prefer using pure functions that receive all data as parameters. `Onyx.connectWithoutView()` should only be used when a library file is unable to get the data with `useOnyx()` (eg. non-React code, network layer, etc.). Never add a reference to `Onyx.connectWithoutView()` just because nearby code uses it. See [Reading Onyx data: `useOnyx` vs `Onyx.connectWithoutView`](/contributingGuides/philosophies/ONYX-DATA-MANAGEMENT.md#reading-onyx-data-useonyx-vs-onyxconnectwithoutview) for the full rules.
`useOnyx()` is the standard for accessing Onyx data for React components. Non-React library files should always prefer using pure functions that receive all data as parameters. `Onyx.connectWithoutView()` should only be used when a library file is unable to get the data with `useOnyx()` (eg. non-React code, network layer, etc.). Never add a reference to `Onyx.connectWithoutView()` just because nearby code uses it. See [Reading Onyx data: `useOnyx`, `Onyx.get()` and `Onyx.connectWithoutView`](/contributingGuides/philosophies/ONYX-DATA-MANAGEMENT.md#reading-onyx-data-useonyx-onyxget-and-onyxconnectwithoutview) for the full rules.

```ts
// GOOD ✅ — non-React network layer keeps the auth token in module state
Expand Down
Loading
Loading