From 4211f1476bd7fb6bcdd963a5387947d56536a51c Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 4 Oct 2026 09:21:39 +0000 Subject: [PATCH 1/4] docs(vue): Add DataClientPlugin API page Vue-only page covering the managers, initialState, Controller and gcPolicy options, the $dataClient global property, and why awaited composables need + + +``` + +`$dataClient` is typed as `Controller` on `ComponentCustomProperties`. + +## Using composables + +Composables like [useSuspense()](./useSuspense.md) must run during a component's `setup`, so Vue +knows which app's store to use. Awaiting them requires ` +``` + +Components that `await` must render inside a [``](https://vuejs.org/guide/built-ins/suspense.html) +boundary. diff --git a/docs/core/api/DataProvider.md b/docs/core/api/DataProvider.md index 1faf202536a6..23f783193e5f 100644 --- a/docs/core/api/DataProvider.md +++ b/docs/core/api/DataProvider.md @@ -48,9 +48,10 @@ export interface State { readonly meta: { readonly [key: string]: { readonly date: number; - readonly error?: ErrorTypes; + readonly fetchedAt: number; readonly expiresAt: number; readonly prevExpiresAt?: number; + readonly error?: ErrorTypes; readonly invalidated?: boolean; readonly errorPolicy?: 'hard' | 'soft' | undefined; }; diff --git a/docs/core/api/DevToolsManager.md b/docs/core/api/DevToolsManager.md index 7f2194ed06b1..c4c0c3369054 100644 --- a/docs/core/api/DevToolsManager.md +++ b/docs/core/api/DevToolsManager.md @@ -124,7 +124,7 @@ __DC_CONTROLLERS__.get('Data Client: My App').getState(); This is useful for AI coding assistants using the [Chrome DevTools MCP](https://developer.chrome.com/blog/chrome-devtools-mcp) or [Expo MCP](https://docs.expo.dev/eas/ai/mcp/) to programmatically inspect and interact -with the store. Each :react[[DataProvider](/docs/api/DataProvider)]:vue[installed DataClientPlugin] registers independently, so +with the store. Each :react[[DataProvider](/docs/api/DataProvider)]:vue[installed [DataClientPlugin](./DataClientPlugin.md)] registers independently, so multiple :react[providers]:vue[apps] on the same page are fully supported. Controllers are removed from the map when `cleanup()` is called. diff --git a/docs/core/api/Manager.md b/docs/core/api/Manager.md index 45843e65ba30..86b6c0315a98 100644 --- a/docs/core/api/Manager.md +++ b/docs/core/api/Manager.md @@ -75,7 +75,7 @@ have internal state, so it is important to not constantly recreate them. :::vue -Use the `managers` option of [DataClientPlugin](../getting-started/installation.md). The plugin is +Use the [managers](./DataClientPlugin.md#managers) option of [DataClientPlugin](./DataClientPlugin.md). The plugin is installed once per app, so managers are created once. ::: diff --git a/docs/core/api/getDefaultManagers.md b/docs/core/api/getDefaultManagers.md index e4358106aee1..dbd18870a33c 100644 --- a/docs/core/api/getDefaultManagers.md +++ b/docs/core/api/getDefaultManagers.md @@ -8,7 +8,7 @@ import StackBlitz from '@site/src/components/StackBlitz'; # getDefaultManagers() -`getDefaultManagers` returns an Array of [Managers](./Manager.md) to be sent to :react[[<DataProvider />](./DataProvider.md)]:vue[[DataClientPlugin](../getting-started/installation.md#add-provider-at-top-level-component)]. +`getDefaultManagers` returns an Array of [Managers](./Manager.md) to be sent to :react[[<DataProvider />](./DataProvider.md)]:vue[[DataClientPlugin](./DataClientPlugin.md)]. This makes it simple to configure and add custom [Managers](./Manager.md), while remaining robust against any potential changes to the default managers. @@ -63,8 +63,8 @@ app.mount('#app'); ``` When `managers` is omitted, `DataClientPlugin` uses `getDefaultManagers()` with no arguments. -See [installation](../getting-started/installation.md#add-provider-at-top-level-component) for the -other `DataClientPlugin` options. +See [DataClientPlugin](./DataClientPlugin.md#options) for the +other options. ::: diff --git a/docs/core/api/mockInitialState.md b/docs/core/api/mockInitialState.md index 50d77bdbc6fa..f2bac79f6794 100644 --- a/docs/core/api/mockInitialState.md +++ b/docs/core/api/mockInitialState.md @@ -23,7 +23,7 @@ This prop specifies the [fixtures](./Fixtures.md) to use data from. Each item re [Endpoint](/rest/api/Endpoint) and params. `Result` contains the JSON response expected from said fetch. -This can be used as the :react[initialState prop for [<DataProvider /\>](./DataProvider)]:vue[`initialState` option for [DataClientPlugin](../getting-started/installation.md)] +This can be used as the :react[initialState prop for [<DataProvider /\>](./DataProvider)]:vue[[initialState option](./DataClientPlugin.md#initialState) for [DataClientPlugin](./DataClientPlugin.md)] ## Example diff --git a/docs/core/api/useController.md b/docs/core/api/useController.md index 578cbc2b4553..a0e5b5df60ed 100644 --- a/docs/core/api/useController.md +++ b/docs/core/api/useController.md @@ -76,8 +76,8 @@ function MyComponent({ id }) { ``` `useController()` must be called inside ` + + +``` + +## Using composables + +Composables like [useSuspense()](https://dataclient.io/docs/api/useSuspense) must run during a component's `setup`, so Vue +knows which app's store to use. Awaiting them requires ` +``` + +Components that `await` must render inside a [``](https://vuejs.org/guide/built-ins/suspense.html) +boundary. diff --git a/.agents/skills/data-client-setup/references/DataProvider.md b/.agents/skills/data-client-setup/references/DataProvider.md index 73cee8e5d20a..0f8cad55d075 100644 --- a/.agents/skills/data-client-setup/references/DataProvider.md +++ b/.agents/skills/data-client-setup/references/DataProvider.md @@ -91,6 +91,7 @@ interface ProviderProps { managers?: Manager[]; initialState?: State; Controller?: typeof Controller; + gcPolicy?: GCInterface; devButton?: | 'bottom-right' | 'bottom-left' @@ -114,9 +115,10 @@ export interface State { readonly meta: { readonly [key: string]: { readonly date: number; - readonly error?: ErrorTypes; + readonly fetchedAt: number; readonly expiresAt: number; readonly prevExpiresAt?: number; + readonly error?: ErrorTypes; readonly invalidated?: boolean; readonly errorPolicy?: 'hard' | 'soft' | undefined; }; @@ -179,6 +181,35 @@ const RealApp = ( ); ``` +### gcPolicy?: GCInterface {#gcPolicy} + +Removes data from the store once no component uses it and it has gone stale. Defaults to +`new GCPolicy()`. + +```tsx +import { DataProvider, GCPolicy } from '@data-client/react'; + +const gcPolicy = new GCPolicy({ intervalMS: 60 * 1000 * 10 }); + +const RealApp = ( + + + +); +``` + +```ts title="GCPolicy options" +new GCPolicy({ + // how often to sweep (default 5 minutes) + intervalMS: 60 * 1000 * 5, + // how many stale lifetimes before data is removed (default 2) + expiryMultiplier: 2, + // or choose when unused data is removed (replaces expiryMultiplier) + // here: one minute after it goes stale + expiresAt: ({ expiresAt }) => expiresAt + 60 * 1000, +}); +``` + ### devButton In development, a small button will appear that gives easy access to [browser devtools](https://dataclient.io/docs/getting-started/debugging) if diff --git a/.agents/skills/data-client-setup/references/getDefaultManagers.vue.md b/.agents/skills/data-client-setup/references/getDefaultManagers.vue.md index 362ad7d84a3f..299d18b75867 100644 --- a/.agents/skills/data-client-setup/references/getDefaultManagers.vue.md +++ b/.agents/skills/data-client-setup/references/getDefaultManagers.vue.md @@ -2,7 +2,7 @@ # getDefaultManagers() -`getDefaultManagers` returns an Array of [Managers](https://dataclient.io/vue/api/Manager) to be sent to [DataClientPlugin](./installation.vue.md#add-provider-at-top-level-component). +`getDefaultManagers` returns an Array of [Managers](https://dataclient.io/vue/api/Manager) to be sent to [DataClientPlugin](./DataClientPlugin.md). This makes it simple to configure and add custom [Managers](https://dataclient.io/vue/api/Manager), while remaining robust against any potential changes to the default managers. @@ -29,8 +29,8 @@ app.mount('#app'); ``` When `managers` is omitted, `DataClientPlugin` uses `getDefaultManagers()` with no arguments. -See [installation](./installation.vue.md#add-provider-at-top-level-component) for the -other `DataClientPlugin` options. +See [DataClientPlugin](./DataClientPlugin.md#options) for the +other options. ## Arguments diff --git a/.agents/skills/data-client-setup/references/installation.vue.md b/.agents/skills/data-client-setup/references/installation.vue.md index bc39ca65a263..71e4237b65de 100644 --- a/.agents/skills/data-client-setup/references/installation.vue.md +++ b/.agents/skills/data-client-setup/references/installation.vue.md @@ -31,6 +31,8 @@ app.use(DataClientPlugin, { app.mount('#app'); ``` +See [DataClientPlugin](./DataClientPlugin.md) for all options. + [Next: Define Data »](https://dataclient.io/vue/getting-started/resource) ## Example diff --git a/.agents/skills/data-client-vue/SKILL.md b/.agents/skills/data-client-vue/SKILL.md index 1ddcf0360a45..07a5ea11c08d 100644 --- a/.agents/skills/data-client-vue/SKILL.md +++ b/.agents/skills/data-client-vue/SKILL.md @@ -5,7 +5,7 @@ license: Apache 2.0 --- ## Setup -Install `DataClientPlugin` once with `app.use(DataClientPlugin)` ([installation](references/installation.md); +Install [DataClientPlugin](references/DataClientPlugin.md) once with `app.use(DataClientPlugin)` ([installation](references/installation.md); apply the skill "data-client-setup" to set it up). Composables only work inside ` + + +``` + +## Using composables + +Composables like [useSuspense()](./useSuspense.md) must run during a component's `setup`, so Vue +knows which app's store to use. Awaiting them requires ` +``` + +Components that `await` must render inside a [``](https://vuejs.org/guide/built-ins/suspense.html) +boundary. diff --git a/.agents/skills/data-client-vue/references/getDefaultManagers.md b/.agents/skills/data-client-vue/references/getDefaultManagers.md index 79cc0d6e9040..299d18b75867 100644 --- a/.agents/skills/data-client-vue/references/getDefaultManagers.md +++ b/.agents/skills/data-client-vue/references/getDefaultManagers.md @@ -2,7 +2,7 @@ # getDefaultManagers() -`getDefaultManagers` returns an Array of [Managers](https://dataclient.io/vue/api/Manager) to be sent to [DataClientPlugin](./installation.md#add-provider-at-top-level-component). +`getDefaultManagers` returns an Array of [Managers](https://dataclient.io/vue/api/Manager) to be sent to [DataClientPlugin](./DataClientPlugin.md). This makes it simple to configure and add custom [Managers](https://dataclient.io/vue/api/Manager), while remaining robust against any potential changes to the default managers. @@ -29,8 +29,8 @@ app.mount('#app'); ``` When `managers` is omitted, `DataClientPlugin` uses `getDefaultManagers()` with no arguments. -See [installation](./installation.md#add-provider-at-top-level-component) for the -other `DataClientPlugin` options. +See [DataClientPlugin](./DataClientPlugin.md#options) for the +other options. ## Arguments diff --git a/.agents/skills/data-client-vue/references/installation.md b/.agents/skills/data-client-vue/references/installation.md index bc39ca65a263..71e4237b65de 100644 --- a/.agents/skills/data-client-vue/references/installation.md +++ b/.agents/skills/data-client-vue/references/installation.md @@ -31,6 +31,8 @@ app.use(DataClientPlugin, { app.mount('#app'); ``` +See [DataClientPlugin](./DataClientPlugin.md) for all options. + [Next: Define Data »](https://dataclient.io/vue/getting-started/resource) ## Example diff --git a/.agents/skills/data-client-vue/references/useController.md b/.agents/skills/data-client-vue/references/useController.md index 6ad0b73f00d9..64807e997135 100644 --- a/.agents/skills/data-client-vue/references/useController.md +++ b/.agents/skills/data-client-vue/references/useController.md @@ -29,8 +29,8 @@ and [setResponse](./Controller.md#setResponse) ``` `useController()` must be called inside `