@hitch42/applet 0.1.0-beta.9 → 0.1.1-beta.10

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.
Files changed (164) hide show
  1. package/dist/_internal/client.js +120 -11
  2. package/dist/_internal/log-context.d.ts +34 -0
  3. package/dist/_internal/log-context.js +2 -0
  4. package/dist/_internal/server.js +112 -57
  5. package/dist/applet.js +12 -12
  6. package/dist/build-Bh_S5BUv.js +2 -0
  7. package/dist/{build-CAb26kMY.js → build-CEfFoIZZ.js} +1 -1
  8. package/dist/{ci-5qWl7lT3.js → ci-BKw14X2h.js} +14 -13
  9. package/dist/client.d.ts +2 -2
  10. package/dist/{contract-rP_eV9PK.d.ts → contract-CsUpTBe0.d.ts} +1 -1
  11. package/dist/{deploy-D_OFJ6-Q.js → deploy-wGYjwXrx.js} +139 -88
  12. package/dist/{generate-CBPnHoqX.js → generate-BEIYs17x.js} +54 -22
  13. package/dist/generate-Dox-OYt6.js +2 -0
  14. package/dist/headers-DkNr9MLJ.js +17 -0
  15. package/dist/index.d.ts +3 -2
  16. package/dist/index.js +2 -1
  17. package/dist/{init-tfzwuYnk.js → init-6oGPM46R.js} +10 -15
  18. package/dist/{load-config-BYSxDVAl.js → load-config-xEdTXs0y.js} +2 -2
  19. package/dist/log-context-zu8U9Sjm.js +73 -0
  20. package/dist/{login-C7RKmmTe.js → login-CUx3TmFQ.js} +1 -1
  21. package/dist/{logs-DgjgAxj2.js → logs-DSjuEN0Q.js} +20 -22
  22. package/dist/{manifest-DD_SGkS6.d.ts → manifest-C6_F4bL8.d.ts} +5 -1
  23. package/dist/{manifest-Bp87Uz0a.js → manifest-CJSL9GuC.js} +20 -4
  24. package/dist/{project-D6XHllmC.js → project-BRZGd6xq.js} +197 -16
  25. package/dist/query-cache-CXmAyLv3.js +82 -0
  26. package/dist/react.d.ts +2 -1
  27. package/dist/react.js +59 -39
  28. package/dist/{schedules-dhU1yyFr.js → schedules-C8_Svr4h.js} +1 -1
  29. package/dist/server.d.ts +8 -3
  30. package/dist/server.js +29 -8
  31. package/dist/telephony.d.ts +24 -4
  32. package/dist/telephony.js +135 -16
  33. package/dist/{variables-Bwnr7oxf.js → variables-DT5RyHdH.js} +13 -13
  34. package/dist/vite.d.ts +3 -60
  35. package/dist/vite.js +50 -15
  36. package/dist/{workflow-engine-MogejNfF.js → workflow-engine-BOTzURKM.js} +1 -7
  37. package/dist/{workspace-XVtM12ZC.js → workspace-D0dnnlxL.js} +33 -38
  38. package/package.json +13 -6
  39. package/scaffold/.agents/skills/hitch-applets/SKILL.md +29 -3
  40. package/scaffold/.agents/skills/hitch-applets/references/manifest.md +8 -0
  41. package/scaffold/.agents/skills/hitch-applets/references/markdown.md +2 -0
  42. package/scaffold/.agents/skills/hitch-applets/references/records.md +2 -0
  43. package/scaffold/.agents/skills/hitch-data/SKILL.md +2 -1
  44. package/scaffold/.agents/skills/hitch-data/references/attributes.md +7 -1
  45. package/scaffold/.agents/skills/hitch-data/references/limits.md +13 -13
  46. package/scaffold/.agents/skills/hitch-theory/SKILL.md +3 -2
  47. package/scaffold/.agents/skills/react-best-practices/SKILL.md +127 -0
  48. package/scaffold/.agents/skills/react-best-practices/rules/advanced-effect-event-deps.md +50 -0
  49. package/scaffold/.agents/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  50. package/scaffold/.agents/skills/react-best-practices/rules/advanced-init-once.md +42 -0
  51. package/scaffold/.agents/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
  52. package/scaffold/.agents/skills/react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
  53. package/scaffold/.agents/skills/react-best-practices/rules/async-defer-await.md +82 -0
  54. package/scaffold/.agents/skills/react-best-practices/rules/async-dependencies.md +48 -0
  55. package/scaffold/.agents/skills/react-best-practices/rules/async-parallel.md +24 -0
  56. package/scaffold/.agents/skills/react-best-practices/rules/bundle-analyzable-paths.md +42 -0
  57. package/scaffold/.agents/skills/react-best-practices/rules/bundle-barrel-imports.md +39 -0
  58. package/scaffold/.agents/skills/react-best-practices/rules/bundle-conditional.md +35 -0
  59. package/scaffold/.agents/skills/react-best-practices/rules/bundle-defer-third-party.md +46 -0
  60. package/scaffold/.agents/skills/react-best-practices/rules/bundle-dynamic-imports.md +38 -0
  61. package/scaffold/.agents/skills/react-best-practices/rules/bundle-preload.md +40 -0
  62. package/scaffold/.agents/skills/react-best-practices/rules/client-event-listeners.md +78 -0
  63. package/scaffold/.agents/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
  64. package/scaffold/.agents/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  65. package/scaffold/.agents/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
  66. package/scaffold/.agents/skills/react-best-practices/rules/js-cache-function-results.md +58 -0
  67. package/scaffold/.agents/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  68. package/scaffold/.agents/skills/react-best-practices/rules/js-cache-storage.md +56 -0
  69. package/scaffold/.agents/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  70. package/scaffold/.agents/skills/react-best-practices/rules/js-early-exit.md +50 -0
  71. package/scaffold/.agents/skills/react-best-practices/rules/js-flatmap-filter.md +51 -0
  72. package/scaffold/.agents/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  73. package/scaffold/.agents/skills/react-best-practices/rules/js-index-maps.md +37 -0
  74. package/scaffold/.agents/skills/react-best-practices/rules/js-length-check-first.md +50 -0
  75. package/scaffold/.agents/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  76. package/scaffold/.agents/skills/react-best-practices/rules/js-request-idle-callback.md +104 -0
  77. package/scaffold/.agents/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  78. package/scaffold/.agents/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  79. package/scaffold/.agents/skills/react-best-practices/rules/rendering-activity.md +26 -0
  80. package/scaffold/.agents/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
  81. package/scaffold/.agents/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
  82. package/scaffold/.agents/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  83. package/scaffold/.agents/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
  84. package/scaffold/.agents/skills/react-best-practices/rules/rendering-resource-hints.md +81 -0
  85. package/scaffold/.agents/skills/react-best-practices/rules/rendering-script-defer-async.md +36 -0
  86. package/scaffold/.agents/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  87. package/scaffold/.agents/skills/react-best-practices/rules/rendering-usetransition-loading.md +43 -0
  88. package/scaffold/.agents/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  89. package/scaffold/.agents/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  90. package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  91. package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  92. package/scaffold/.agents/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
  93. package/scaffold/.agents/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
  94. package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
  95. package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo.md +44 -0
  96. package/scaffold/.agents/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  97. package/scaffold/.agents/skills/react-best-practices/rules/rerender-no-inline-components.md +75 -0
  98. package/scaffold/.agents/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  99. package/scaffold/.agents/skills/react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
  100. package/scaffold/.agents/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  101. package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-deferred-value.md +59 -0
  102. package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  103. package/scaffold/.agents/skills/tanstack-query/SKILL.md +136 -0
  104. package/scaffold/.agents/skills/tanstack-query/references/compositions/automatic-invalidation-after-mutations.md +124 -0
  105. package/scaffold/.agents/skills/tanstack-query/references/compositions/broadcast-realtime-and-multi-tab-synchronization.md +150 -0
  106. package/scaffold/.agents/skills/tanstack-query/references/compositions/compose-query-with-tanstack-router-and-start.md +248 -0
  107. package/scaffold/.agents/skills/tanstack-query/references/compositions/enforce-query-best-practices-with-eslint.md +167 -0
  108. package/scaffold/.agents/skills/tanstack-query/references/compositions/persist-offline-and-restore-caches.md +181 -0
  109. package/scaffold/.agents/skills/tanstack-query/references/compositions/query-data-and-forms.md +156 -0
  110. package/scaffold/.agents/skills/tanstack-query/references/core/build-query-abstractions.md +130 -0
  111. package/scaffold/.agents/skills/tanstack-query/references/core/cancel-queries-and-consume-abort-signals.md +176 -0
  112. package/scaffold/.agents/skills/tanstack-query/references/core/concurrent-optimistic-updates.md +135 -0
  113. package/scaffold/.agents/skills/tanstack-query/references/core/coordinate-query-execution.md +188 -0
  114. package/scaffold/.agents/skills/tanstack-query/references/core/design-query-keys-and-options.md +182 -0
  115. package/scaffold/.agents/skills/tanstack-query/references/core/fetch-and-observe-queries.md +193 -0
  116. package/scaffold/.agents/skills/tanstack-query/references/core/implement-optimistic-updates-and-cache-writes.md +168 -0
  117. package/scaffold/.agents/skills/tanstack-query/references/core/paginate-and-build-infinite-queries.md +188 -0
  118. package/scaffold/.agents/skills/tanstack-query/references/core/seed-placeholder-select-and-transform-data.md +188 -0
  119. package/scaffold/.agents/skills/tanstack-query/references/core/selectors-and-derived-state.md +145 -0
  120. package/scaffold/.agents/skills/tanstack-query/references/core/tune-defaults-freshness-retries-and-refetching.md +172 -0
  121. package/scaffold/.agents/skills/tanstack-query/references/core/understand-query-internals-and-observers.md +104 -0
  122. package/scaffold/.agents/skills/tanstack-query/references/core/write-mutations-and-invalidate-related-queries.md +183 -0
  123. package/scaffold/.agents/skills/tanstack-query/references/framework/debug-with-devtools.md +169 -0
  124. package/scaffold/.agents/skills/tanstack-query/references/framework/handle-status-and-errors.md +119 -0
  125. package/scaffold/.agents/skills/tanstack-query/references/framework/shape-data-and-render-efficiently.md +184 -0
  126. package/scaffold/.agents/skills/tanstack-query/references/framework/use-framework-adapter-reactivity.md +185 -0
  127. package/scaffold/.agents/skills/tanstack-query/references/framework/use-suspense-and-error-boundaries.md +208 -0
  128. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/migrate-major-versions-and-codemods.md +169 -0
  129. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/prefetch-and-remove-request-waterfalls.md +228 -0
  130. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/setup-query-client-and-providers.md +161 -0
  131. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/ssr-hydration-and-streaming.md +209 -0
  132. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/test-query-code.md +160 -0
  133. package/scaffold/.agents/skills/tanstack-router/SKILL.md +134 -0
  134. package/scaffold/.agents/skills/tanstack-router/references/compositions/router-query.md +412 -0
  135. package/scaffold/.agents/skills/tanstack-router/references/react-router.md +495 -0
  136. package/scaffold/.agents/skills/tanstack-router/references/router-core/auth-and-guards.md +495 -0
  137. package/scaffold/.agents/skills/tanstack-router/references/router-core/code-splitting.md +318 -0
  138. package/scaffold/.agents/skills/tanstack-router/references/router-core/data-loading.md +490 -0
  139. package/scaffold/.agents/skills/tanstack-router/references/router-core/index.md +158 -0
  140. package/scaffold/.agents/skills/tanstack-router/references/router-core/navigation.md +433 -0
  141. package/scaffold/.agents/skills/tanstack-router/references/router-core/not-found-and-errors.md +436 -0
  142. package/scaffold/.agents/skills/tanstack-router/references/router-core/path-params.md +383 -0
  143. package/scaffold/.agents/skills/tanstack-router/references/router-core/search-params.md +343 -0
  144. package/scaffold/.agents/skills/tanstack-router/references/router-core/ssr.md +462 -0
  145. package/scaffold/.agents/skills/tanstack-router/references/router-core/type-safety.md +493 -0
  146. package/scaffold/.agents/skills/tanstack-router/references/router-plugin.md +250 -0
  147. package/scaffold/.agents/skills/tanstack-router/references/virtual-file-routes.md +215 -0
  148. package/scaffold/.agents/skills/web-design-guidelines/SKILL.md +184 -0
  149. package/scaffold/.github/workflows/hitch.yml +1 -1
  150. package/scaffold/AGENTS.md +2 -2
  151. package/scaffold/applet/src/client/components/ui/alert.tsx +1 -1
  152. package/scaffold/applet/src/client/components/ui/button.tsx +1 -1
  153. package/scaffold/applet/src/client/components/ui/checkbox.tsx +1 -1
  154. package/scaffold/applet/src/client/components/ui/dialog.tsx +2 -2
  155. package/scaffold/applet/src/client/components/ui/dropdown-menu.tsx +2 -2
  156. package/scaffold/applet/src/client/components/ui/input-group.tsx +2 -2
  157. package/scaffold/applet/src/client/components/ui/select.tsx +2 -2
  158. package/scaffold/applet/src/client/components/ui/sheet.tsx +2 -2
  159. package/scaffold/applet/src/client/components/ui/spinner.tsx +2 -1
  160. package/scaffold/applet/src/client/components/ui/tabs.tsx +1 -1
  161. package/scaffold/applet/src/client/lib/utils.ts +1 -6
  162. package/scaffold/applet/src/client/styles/globals.css +2 -0
  163. package/dist/build-BfbTbt_r.js +0 -2
  164. package/dist/generate-BgepN4-b.js +0 -2
@@ -0,0 +1,135 @@
1
+ ---
2
+ name: core/concurrent-optimistic-updates
3
+ description: >
4
+ Use this when multiple optimistic mutations can overlap: mutation variables,
5
+ submittedAt keys, scoped mutationKey filters, isMutating guards, cancellation,
6
+ rollback context, filtered list updates, and avoiding windows of inconsistent
7
+ UI during concurrent writes.
8
+ type: core
9
+ library: TanStack Query
10
+ library_version: "5.101.0"
11
+ requires:
12
+ - core/implement-optimistic-updates-and-cache-writes
13
+ - core/cancel-queries-and-consume-abort-signals
14
+ sources:
15
+ - TanStack/query:docs/framework/react/guides/optimistic-updates.md
16
+ - TanStack/query:docs/framework/react/reference/useMutationState.md
17
+ ---
18
+
19
+ ## Core Patterns
20
+
21
+ Concurrent optimistic updates need per-mutation identity and scoped invalidation. A rollback or invalidation from one mutation should not erase another mutation that is still pending.
22
+
23
+ ### Scope related mutations
24
+
25
+ ```tsx
26
+ const mutation = useMutation({
27
+ mutationKey: ["items"],
28
+ mutationFn: toggleItem,
29
+ onMutate: async ({ id }) => {
30
+ await queryClient.cancelQueries({ queryKey: ["items", "detail", id] });
31
+ const previousItem = queryClient.getQueryData<Item>(["items", "detail", id]);
32
+
33
+ queryClient.setQueryData<Item>(["items", "detail", id], (item) =>
34
+ item ? { ...item, isActive: !item.isActive } : item,
35
+ );
36
+
37
+ return { previousItem };
38
+ },
39
+ onError: (_error, variables, context) => {
40
+ queryClient.setQueryData(["items", "detail", variables.id], context?.previousItem);
41
+ },
42
+ onSettled: () => {
43
+ if (queryClient.isMutating({ mutationKey: ["items"] }) === 1) {
44
+ return queryClient.invalidateQueries({ queryKey: ["items"] });
45
+ }
46
+ },
47
+ });
48
+ ```
49
+
50
+ Use `queryClient.isMutating()` imperatively inside the callback so the count is current at the moment invalidation would run.
51
+
52
+ ### Render pending variables with stable keys
53
+
54
+ ```tsx
55
+ const pendingAdds = useMutationState<string>({
56
+ filters: { mutationKey: ["todos", "add"], status: "pending" },
57
+ select: (mutation) => `${mutation.state.submittedAt}:${mutation.state.variables}`,
58
+ });
59
+ ```
60
+
61
+ `submittedAt` distinguishes multiple pending mutations with the same variables.
62
+
63
+ ## Common Mistakes
64
+
65
+ ### CRITICAL One mutation invalidation reverts another optimistic update
66
+
67
+ Wrong:
68
+
69
+ ```ts
70
+ onSettled: () => queryClient.invalidateQueries({ queryKey: ["items"] });
71
+ ```
72
+
73
+ Correct:
74
+
75
+ ```ts
76
+ onSettled: () => {
77
+ if (queryClient.isMutating({ mutationKey: ["items"] }) === 1) {
78
+ return queryClient.invalidateQueries({ queryKey: ["items"] });
79
+ }
80
+ };
81
+ ```
82
+
83
+ Skip intermediate invalidations while related optimistic mutations are still in flight.
84
+
85
+ ### HIGH Optimistic list update ignores current filters
86
+
87
+ Wrong:
88
+
89
+ ```ts
90
+ queryClient.setQueryData(["items", "list", filters], (items) =>
91
+ items?.map((item) => (item.id === updated.id ? updated : item)),
92
+ );
93
+ ```
94
+
95
+ Correct:
96
+
97
+ ```ts
98
+ queryClient.setQueryData(["items", "list", filters], (items) =>
99
+ items
100
+ ?.map((item) => (item.id === updated.id ? updated : item))
101
+ .filter((item) => matchesFilters(item, filters)),
102
+ );
103
+ ```
104
+
105
+ If the server would remove the updated item from the filtered list, the optimistic cache update should do the same.
106
+
107
+ ### HIGH Pending optimistic rows share unstable keys
108
+
109
+ Wrong:
110
+
111
+ ```tsx
112
+ {
113
+ variables.map((title) => <li key={title}>{title}</li>);
114
+ }
115
+ ```
116
+
117
+ Correct:
118
+
119
+ ```tsx
120
+ const pending = useMutationState({
121
+ filters: { mutationKey: ["todos", "add"], status: "pending" },
122
+ select: (mutation) => ({
123
+ variables: mutation.state.variables,
124
+ submittedAt: mutation.state.submittedAt,
125
+ }),
126
+ });
127
+
128
+ {
129
+ pending.map((todo) => <li key={todo.submittedAt}>{todo.variables.title}</li>);
130
+ }
131
+ ```
132
+
133
+ Use mutation metadata to keep concurrent optimistic rows distinct.
134
+
135
+ Source: TanStack/query:docs/framework/react/guides/optimistic-updates.md
@@ -0,0 +1,188 @@
1
+ ---
2
+ name: core/coordinate-query-execution
3
+ description: >
4
+ Use this when coordinating enabled, skipToken, dependent queries, useQueries,
5
+ parallel queries, disabled queries, background fetching indicators, isFetching,
6
+ fetchStatus, and declarative refetch behavior.
7
+ type: core
8
+ library: TanStack Query
9
+ library_version: "5.101.0"
10
+ requires:
11
+ - core/fetch-and-observe-queries
12
+ - core/tune-defaults-freshness-retries-and-refetching
13
+ sources:
14
+ - TanStack/query:docs/framework/react/guides/dependent-queries.md
15
+ - TanStack/query:docs/framework/react/guides/parallel-queries.md
16
+ - TanStack/query:docs/framework/react/guides/disabling-queries.md
17
+ - TanStack/query:docs/framework/react/guides/background-fetching-indicators.md
18
+ - TanStack/query:docs/framework/react/reference/useQueries.md
19
+ ---
20
+
21
+ ## Setup
22
+
23
+ ```tsx
24
+ import { useQuery } from "@tanstack/react-query";
25
+
26
+ export function Projects(props: { userId?: string }) {
27
+ const projects = useQuery({
28
+ queryKey: ["projects", props.userId],
29
+ queryFn: async () => [{ id: "p1", userId: props.userId }],
30
+ enabled: Boolean(props.userId),
31
+ });
32
+
33
+ return <pre>{JSON.stringify(projects.data ?? [])}</pre>;
34
+ }
35
+ ```
36
+
37
+ ## Core Patterns
38
+
39
+ ### Gate by dependency
40
+
41
+ ```ts
42
+ import { useQuery } from "@tanstack/react-query";
43
+
44
+ export function useUserProjects(userId: string | undefined) {
45
+ return useQuery({
46
+ queryKey: ["projects", userId],
47
+ queryFn: async () => [{ id: "p1", userId }],
48
+ enabled: userId !== undefined,
49
+ });
50
+ }
51
+ ```
52
+
53
+ ### Run dynamic parallel queries
54
+
55
+ ```ts
56
+ import { useQueries } from "@tanstack/react-query";
57
+
58
+ export function useMessages(ids: Array<string>) {
59
+ return useQueries({
60
+ queries: ids.map((id) => ({
61
+ queryKey: ["message", id],
62
+ queryFn: async () => ({ id, text: "Hello" }),
63
+ })),
64
+ });
65
+ }
66
+ ```
67
+
68
+ ### Show background refresh separately
69
+
70
+ ```tsx
71
+ import { useIsFetching } from "@tanstack/react-query";
72
+
73
+ export function GlobalRefreshIndicator() {
74
+ const count = useIsFetching();
75
+ return count > 0 ? <p>Refreshing</p> : null;
76
+ }
77
+ ```
78
+
79
+ ## Common Mistakes
80
+
81
+ ### HIGH Imperative disabled query
82
+
83
+ Wrong:
84
+
85
+ ```ts
86
+ import { useQuery } from "@tanstack/react-query";
87
+
88
+ export function useSearch(term: string) {
89
+ return useQuery({
90
+ queryKey: ["search"],
91
+ queryFn: async () => [term],
92
+ enabled: false,
93
+ });
94
+ }
95
+ ```
96
+
97
+ Correct:
98
+
99
+ ```ts
100
+ import { useQuery } from "@tanstack/react-query";
101
+
102
+ export function useSearch(term: string) {
103
+ return useQuery({
104
+ queryKey: ["search", term],
105
+ queryFn: async () => [term],
106
+ enabled: term.length > 0,
107
+ });
108
+ }
109
+ ```
110
+
111
+ Permanent disabling opts out of normal invalidation and dependency-driven cache behavior.
112
+
113
+ Source: TanStack/query:docs/framework/react/guides/disabling-queries.md
114
+
115
+ ### HIGH Duplicate useQueries keys
116
+
117
+ Wrong:
118
+
119
+ ```ts
120
+ import { useQueries } from "@tanstack/react-query";
121
+
122
+ export function useUsers(ids: Array<string>) {
123
+ return useQueries({
124
+ queries: ids.map((id) => ({
125
+ queryKey: ["user"],
126
+ queryFn: async () => ({ id }),
127
+ })),
128
+ });
129
+ }
130
+ ```
131
+
132
+ Correct:
133
+
134
+ ```ts
135
+ import { useQueries } from "@tanstack/react-query";
136
+
137
+ export function useUsers(ids: Array<string>) {
138
+ return useQueries({
139
+ queries: ids.map((id) => ({
140
+ queryKey: ["user", id],
141
+ queryFn: async () => ({ id }),
142
+ })),
143
+ });
144
+ }
145
+ ```
146
+
147
+ Duplicate keys can share placeholder, selected, or cached data between different items.
148
+
149
+ Source: TanStack/query:docs/framework/react/reference/useQueries.md
150
+
151
+ ### MEDIUM Full-page spinner on background refetch
152
+
153
+ Wrong:
154
+
155
+ ```tsx
156
+ import { useQuery } from "@tanstack/react-query";
157
+
158
+ export function Todos() {
159
+ const query = useQuery({
160
+ queryKey: ["todos"],
161
+ queryFn: async () => [{ id: 1 }],
162
+ });
163
+ return query.isFetching ? <p>Loading</p> : <pre>{JSON.stringify(query.data)}</pre>;
164
+ }
165
+ ```
166
+
167
+ Correct:
168
+
169
+ ```tsx
170
+ import { useQuery } from "@tanstack/react-query";
171
+
172
+ export function Todos() {
173
+ const query = useQuery({
174
+ queryKey: ["todos"],
175
+ queryFn: async () => [{ id: 1 }],
176
+ });
177
+ return (
178
+ <pre>
179
+ {query.isFetching ? "Refreshing " : ""}
180
+ {JSON.stringify(query.data ?? [])}
181
+ </pre>
182
+ );
183
+ }
184
+ ```
185
+
186
+ `isFetching` also covers background refreshes after data is already available.
187
+
188
+ Source: TanStack/query:docs/framework/react/guides/background-fetching-indicators.md
@@ -0,0 +1,182 @@
1
+ ---
2
+ name: core/design-query-keys-and-options
3
+ description: >
4
+ Use this when designing queryKey arrays, queryFn inputs, queryOptions,
5
+ infiniteQueryOptions, mutationOptions, skipToken, key factories, or TypeScript
6
+ inference for TanStack Query reads and writes.
7
+ type: core
8
+ library: TanStack Query
9
+ library_version: "5.101.0"
10
+ sources:
11
+ - TanStack/query:docs/framework/react/guides/query-keys.md
12
+ - TanStack/query:docs/framework/react/guides/query-options.md
13
+ - TanStack/query:docs/framework/react/typescript.md
14
+ - TanStack/query:docs/eslint/exhaustive-deps.md
15
+ - TanStack/query:docs/eslint/prefer-query-options.md
16
+ ---
17
+
18
+ ## Setup
19
+
20
+ ```ts
21
+ import { queryOptions } from "@tanstack/react-query";
22
+
23
+ export function todoOptions(todoId: string) {
24
+ return queryOptions({
25
+ queryKey: ["todo", todoId],
26
+ queryFn: async () => ({ id: todoId, title: "Ship skills" }),
27
+ staleTime: 60_000,
28
+ });
29
+ }
30
+ ```
31
+
32
+ ## Core Patterns
33
+
34
+ ### Put every query variable in the key
35
+
36
+ ```ts
37
+ import { queryOptions } from "@tanstack/react-query";
38
+
39
+ export function projectsOptions(teamId: string, page: number) {
40
+ return queryOptions({
41
+ queryKey: ["projects", teamId, page],
42
+ queryFn: async () => ({ teamId, page, items: [] as Array<{ id: string }> }),
43
+ });
44
+ }
45
+ ```
46
+
47
+ ### Share one options factory
48
+
49
+ ```ts
50
+ import { QueryClient, useQuery, queryOptions } from "@tanstack/react-query";
51
+
52
+ export const queryClient = new QueryClient();
53
+
54
+ export function userOptions(userId: string) {
55
+ return queryOptions({
56
+ queryKey: ["user", userId],
57
+ queryFn: async () => ({ id: userId, name: "Tanner" }),
58
+ });
59
+ }
60
+
61
+ export function useUser(userId: string) {
62
+ return useQuery(userOptions(userId));
63
+ }
64
+
65
+ export function preloadUser(userId: string) {
66
+ return queryClient.ensureQueryData(userOptions(userId));
67
+ }
68
+ ```
69
+
70
+ ### Use skipToken for typesafe absence
71
+
72
+ ```ts
73
+ import { skipToken, useQuery } from "@tanstack/react-query";
74
+
75
+ export function useMaybeTodo(todoId: string | undefined) {
76
+ return useQuery({
77
+ queryKey: ["todo", todoId],
78
+ queryFn: todoId ? async () => ({ id: todoId }) : skipToken,
79
+ });
80
+ }
81
+ ```
82
+
83
+ ## Common Mistakes
84
+
85
+ ### CRITICAL Missing variable in key
86
+
87
+ Wrong:
88
+
89
+ ```ts
90
+ import { useQuery } from "@tanstack/react-query";
91
+
92
+ export function useProject(teamId: string) {
93
+ return useQuery({
94
+ queryKey: ["project"],
95
+ queryFn: async () => ({ teamId }),
96
+ });
97
+ }
98
+ ```
99
+
100
+ Correct:
101
+
102
+ ```ts
103
+ import { useQuery } from "@tanstack/react-query";
104
+
105
+ export function useProject(teamId: string) {
106
+ return useQuery({
107
+ queryKey: ["project", teamId],
108
+ queryFn: async () => ({ teamId }),
109
+ });
110
+ }
111
+ ```
112
+
113
+ Query keys define cache identity; missing variables merge distinct data.
114
+
115
+ Source: TanStack/query:docs/framework/react/guides/query-keys.md
116
+
117
+ ### HIGH Key and queryFn drift
118
+
119
+ Wrong:
120
+
121
+ ```ts
122
+ import { useQuery } from "@tanstack/react-query";
123
+
124
+ export function useTodo(todoId: string) {
125
+ return useQuery({ queryKey: ["todo"], queryFn: async () => ({ id: todoId }) });
126
+ }
127
+ ```
128
+
129
+ Correct:
130
+
131
+ ```ts
132
+ import { queryOptions, useQuery } from "@tanstack/react-query";
133
+
134
+ function todoOptions(todoId: string) {
135
+ return queryOptions({
136
+ queryKey: ["todo", todoId],
137
+ queryFn: async () => ({ id: todoId }),
138
+ });
139
+ }
140
+
141
+ export function useTodo(todoId: string) {
142
+ return useQuery(todoOptions(todoId));
143
+ }
144
+ ```
145
+
146
+ Options factories keep identity, fetch behavior, and inference together across hooks and prefetches.
147
+
148
+ Source: TanStack/query:docs/eslint/prefer-query-options.md
149
+
150
+ ### HIGH skipToken inside suspense query
151
+
152
+ Wrong:
153
+
154
+ ```ts
155
+ import { skipToken, useSuspenseQuery } from "@tanstack/react-query";
156
+
157
+ export function useTodo(todoId: string | undefined) {
158
+ return useSuspenseQuery({
159
+ queryKey: ["todo", todoId],
160
+ queryFn: todoId ? async () => ({ id: todoId }) : skipToken,
161
+ });
162
+ }
163
+ ```
164
+
165
+ Correct:
166
+
167
+ ```ts
168
+ import { skipToken, useQuery } from "@tanstack/react-query";
169
+
170
+ export function useTodo(todoId: string | undefined) {
171
+ return useQuery({
172
+ queryKey: ["todo", todoId],
173
+ queryFn: todoId ? async () => ({ id: todoId }) : skipToken,
174
+ });
175
+ }
176
+ ```
177
+
178
+ Suspense queries require a guaranteed query function and cannot be conditionally disabled.
179
+
180
+ Source: TanStack/query:docs/framework/react/guides/suspense.md
181
+
182
+ See also: `compositions/enforce-query-best-practices-with-eslint` for rules that enforce key and options mistakes.
@@ -0,0 +1,193 @@
1
+ ---
2
+ name: core/fetch-and-observe-queries
3
+ description: >
4
+ Use this when reading server state with useQuery, useQueries, createQuery,
5
+ injectQuery, QueryObserver, QueryClient.fetchQuery, ensureQueryData, status,
6
+ fetchStatus, pending, paused, success, and error states.
7
+ type: core
8
+ library: TanStack Query
9
+ library_version: "5.101.0"
10
+ requires:
11
+ - lifecycle/setup-query-client-and-providers
12
+ - core/design-query-keys-and-options
13
+ sources:
14
+ - TanStack/query:docs/framework/react/guides/queries.md
15
+ - TanStack/query:docs/framework/react/guides/query-functions.md
16
+ - TanStack/query:docs/reference/QueryObserver.md
17
+ - TanStack/query:docs/reference/QueryClient.md
18
+ - TanStack/query:docs/eslint/no-void-query-fn.md
19
+ ---
20
+
21
+ ## Setup
22
+
23
+ ```tsx
24
+ import { useQuery } from "@tanstack/react-query";
25
+
26
+ export function Todos() {
27
+ const query = useQuery({
28
+ queryKey: ["todos"],
29
+ queryFn: async () => [{ id: 1, title: "Ship" }],
30
+ });
31
+
32
+ if (query.isPending) return <p>Loading</p>;
33
+ if (query.isError) return <p>{query.error.message}</p>;
34
+ return <pre>{JSON.stringify(query.data)}</pre>;
35
+ }
36
+ ```
37
+
38
+ ## Core Patterns
39
+
40
+ ### Fetch imperatively through QueryClient
41
+
42
+ ```ts
43
+ import { QueryClient } from "@tanstack/react-query";
44
+
45
+ const queryClient = new QueryClient();
46
+
47
+ export function loadTodo(todoId: string) {
48
+ return queryClient.fetchQuery({
49
+ queryKey: ["todo", todoId],
50
+ queryFn: async () => ({ id: todoId }),
51
+ });
52
+ }
53
+ ```
54
+
55
+ ### Ensure cached data for loaders
56
+
57
+ ```ts
58
+ import { QueryClient } from "@tanstack/react-query";
59
+
60
+ const queryClient = new QueryClient();
61
+
62
+ export function ensureTodos() {
63
+ return queryClient.ensureQueryData({
64
+ queryKey: ["todos"],
65
+ queryFn: async () => [{ id: 1 }],
66
+ });
67
+ }
68
+ ```
69
+
70
+ ### Distinguish status from fetchStatus
71
+
72
+ ```tsx
73
+ import { useQuery } from "@tanstack/react-query";
74
+
75
+ export function TodoCount() {
76
+ const query = useQuery({
77
+ queryKey: ["todos"],
78
+ queryFn: async () => [{ id: 1 }],
79
+ });
80
+ const label =
81
+ query.fetchStatus === "fetching" && query.status === "success" ? "Refreshing" : "Ready";
82
+ return (
83
+ <p>
84
+ {query.data?.length ?? 0} {label}
85
+ </p>
86
+ );
87
+ }
88
+ ```
89
+
90
+ ## Common Mistakes
91
+
92
+ ### CRITICAL Void query function
93
+
94
+ Wrong:
95
+
96
+ ```ts
97
+ import { useQuery } from "@tanstack/react-query";
98
+
99
+ export function useTodos() {
100
+ return useQuery({
101
+ queryKey: ["todos"],
102
+ queryFn: async () => {
103
+ await Promise.resolve([{ id: 1 }]);
104
+ },
105
+ });
106
+ }
107
+ ```
108
+
109
+ Correct:
110
+
111
+ ```ts
112
+ import { useQuery } from "@tanstack/react-query";
113
+
114
+ export function useTodos() {
115
+ return useQuery({
116
+ queryKey: ["todos"],
117
+ queryFn: async () => Promise.resolve([{ id: 1 }]),
118
+ });
119
+ }
120
+ ```
121
+
122
+ Query functions must return data; a missing return caches `undefined`.
123
+
124
+ Source: TanStack/query:docs/eslint/no-void-query-fn.md
125
+
126
+ ### HIGH Only checking pending offline
127
+
128
+ Wrong:
129
+
130
+ ```tsx
131
+ import { useQuery } from "@tanstack/react-query";
132
+
133
+ export function Todos() {
134
+ const query = useQuery({
135
+ queryKey: ["todos"],
136
+ queryFn: async () => [{ id: 1 }],
137
+ networkMode: "online",
138
+ });
139
+ return query.isPending ? <p>Loading</p> : <p>{query.fetchStatus}</p>;
140
+ }
141
+ ```
142
+
143
+ Correct:
144
+
145
+ ```tsx
146
+ import { useQuery } from "@tanstack/react-query";
147
+
148
+ export function Todos() {
149
+ const query = useQuery({
150
+ queryKey: ["todos"],
151
+ queryFn: async () => [{ id: 1 }],
152
+ networkMode: "online",
153
+ });
154
+ return query.fetchStatus === "paused" ? <p>Offline</p> : <p>{query.status}</p>;
155
+ }
156
+ ```
157
+
158
+ `status` describes data state; `fetchStatus` describes whether fetching is paused, fetching, or idle.
159
+
160
+ Source: TanStack/query:docs/framework/react/guides/queries.md
161
+
162
+ ### HIGH Using queries for writes
163
+
164
+ Wrong:
165
+
166
+ ```ts
167
+ import { useQuery } from "@tanstack/react-query";
168
+
169
+ export function useSaveTodo(title: string) {
170
+ return useQuery({
171
+ queryKey: ["saveTodo", title],
172
+ queryFn: async () => ({ id: 1, title }),
173
+ });
174
+ }
175
+ ```
176
+
177
+ Correct:
178
+
179
+ ```ts
180
+ import { useMutation } from "@tanstack/react-query";
181
+
182
+ export function useSaveTodo() {
183
+ return useMutation({
184
+ mutationFn: async (title: string) => ({ id: 1, title }),
185
+ });
186
+ }
187
+ ```
188
+
189
+ Queries are for reads; writes need mutation lifecycle hooks, invalidation, rollback, and mutation state.
190
+
191
+ Source: TanStack/query:docs/framework/react/guides/mutations.md
192
+
193
+ See also: `core/tune-defaults-freshness-retries-and-refetching` for how defaults change status behavior.