# useDocyrusInventory URL: /docs/web/hooks/use-docyrus-inventory Shared app-utils inventory cache for Docyrus metadata (apps, data sources with fields/enums/views/forms, users, brands, preferences) plus a post-sign-in load() warm-up hook that drives an application loading dialog. ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/hooks-use-docyrus-inventory ``` **Dependencies:** - [@docyrus/app-utils](https://www.npmjs.com/package/@docyrus/app-utils) - [@docyrus/api-client](https://www.npmjs.com/package/@docyrus/api-client) This module ships two named exports: - `getSharedDocyrusInventory(client)` — returns the process-wide shared `InventoryClient` for a given `RestApiClient`, creating it on first use (memoized in a `WeakMap` keyed by client). Pass the result into `createDataSourceClient` / `createDataViewClient` / `createDataFormClient` (`{ inventory }`) so every client shares one in-memory cache. `null` in → `null` out. - `useDocyrusInventoryLoader(options)` — headless React hook that runs `inventory.load()` once per client (StrictMode-safe) right after sign-in, exposing determinate progress + status so a host app can render a loading dialog before routing to the home page. ## Why this exists The `@docyrus/app-utils` inventory (`createInventoryClient`) caches everything a Docyrus app needs at startup — apps, data sources (with embedded `views` / `forms` / `fields`, and `enums` on select-type fields), users, brands, and tenant preferences — in one `GET /v1/apps/data-sources?expand=views,forms,fields` request (plus a request each for users / brands / preferences). Because the cache lives in the returned client's closure, a **single shared instance** is what lets: 1. a post-sign-in `load()` warm-up populate it behind a progress bar, and 2. every inventory-backed hook (`useDocyrusFormView`, `useDocyrusDataGrid`, `useDocyrusDataViewSelect`, …) read tenant metadata from that same warm cache instead of re-fetching per mount. `getSharedDocyrusInventory` is the single source of that instance; the Docyrus hooks call it internally, so warming the cache once makes their schema / enum / view / form / relation reads cache hits. ## `getSharedDocyrusInventory(client)` ```tsx import { getSharedDocyrusInventory } from '@docyrus/ui/library/hooks/use-docyrus-inventory'; import { createDataSourceClient } from '@docyrus/app-utils'; const inventory = getSharedDocyrusInventory(apiClient); const dataSources = createDataSourceClient(apiClient, { inventory }); // No `expand` → served from the shared cache (fields incl. enums, views, forms embedded) const contacts = await dataSources.getBySlug('crm', 'contacts'); ``` | Parameter | Type | Description | |-----------|------|-------------| | `client` | `RestApiClient \| null \| undefined` | The authenticated API client. | **Returns:** `InventoryClient` (or `null` when `client` is nullish). ## `useDocyrusInventoryLoader(options)` Runs `inventory.load()` once, as soon as it is `enabled` and a `client` exists, and re-runs automatically when the client identity changes (e.g. a tenant switch that rebuilds the client). Failures do not throw — `status` becomes `'error'` and `reload()` retries; the app can still run (inventory-backed reads fall back to the API). ```tsx import { useDocyrusAuth } from '@docyrus/signin'; import { useDocyrusInventoryLoader } from '@docyrus/ui/library/hooks/use-docyrus-inventory'; function InventoryGate({ children }) { const { client, status } = useDocyrusAuth(); const { status: loadStatus, progress, error, reload } = useDocyrusInventoryLoader({ client, enabled: status === 'authenticated' }); if (loadStatus === 'ready') return children; return ( ); } ``` ### Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `client` | `RestApiClient \| null \| undefined` | `—` | The authenticated API client. The loader waits until this is set. | | `enabled` | `boolean` | `true` | Gate the warm-up (e.g. only once authenticated). Still requires a non-null `client`. | | `include` | `InventoryLoadStepId[]` | `['apps','data-sources','users','brands','preferences']` | Which tenant-wide steps to warm. Drop `'users'` when the signed-in user may lack the `Users.Read.All` scope. | | `configAppIds` | `string[]` | `VITE_APP_ID` (if set) | App ids whose config + user-config to warm. Pass `[]` to skip. | | `force` | `boolean` | `true` | Invalidate caches before loading so the warm-up issues fresh network calls. | ### Result | Field | Type | Description | |-------|------|-------------| | `inventory` | `InventoryClient \| null` | The shared inventory for the current client. | | `status` | `'idle' \| 'loading' \| 'ready' \| 'error'` | Warm-up lifecycle. | | `progress` | `InventoryLoadProgress \| null` | Latest progress event — drive a determinate bar with `progress.ratio`. | | `error` | `unknown` | Present when `status === 'error'`. | | `result` | `InventoryLoadResult \| null` | The loaded payload once ready. | | `isLoading` | `boolean` | `true` while warming. | | `isReady` | `boolean` | `true` once warmed successfully. | | `reload` | `() => void` | Re-run the warm-up (Retry button, or after a tenant switch). |