@ic-reactor/react 3.1.1 → 3.1.3
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.
- package/README.md +86 -328
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,386 +1,144 @@
|
|
|
1
1
|
# @ic-reactor/react
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[](https://www.npmjs.com/package/@ic-reactor/react)
|
|
8
|
-
[](https://opensource.org/licenses/MIT)
|
|
9
|
-
[](https://www.typescriptlang.org/)
|
|
10
|
-
</div>
|
|
3
|
+
React bindings for IC Reactor. This package re-exports everything from
|
|
4
|
+
`@ic-reactor/core` and adds hook factories, auth hooks, direct reactor hooks,
|
|
5
|
+
and reusable query or mutation factories built around TanStack Query.
|
|
11
6
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Connect your React application to the Internet Computer Blockchain with full [TanStack Query](https://tanstack.com/query) integration for caching, suspense, and infinite queries.
|
|
15
|
-
|
|
16
|
-
## Features
|
|
17
|
-
|
|
18
|
-
- ⚛️ **TanStack Query Integration** — Full power of React Query (caching, refetching, suspense, infinite queries)
|
|
19
|
-
- � **End-to-End Type Safety** — Automatic type inference from your Candid files
|
|
20
|
-
- � **Auto Transformations** — `DisplayReactor` converts BigInt to string, Principal to text, and more
|
|
21
|
-
- 📦 **Result Unwrapping** — Automatic `Ok`/`Err` handling from Candid Result types
|
|
22
|
-
- 🔐 **Authentication** — Easy-to-use hooks with Internet Identity integration
|
|
23
|
-
- 🏗️ **Multi-Actor Support** — Manage multiple canisters with shared authentication
|
|
24
|
-
|
|
25
|
-
## Installation
|
|
7
|
+
## Install
|
|
26
8
|
|
|
27
9
|
```bash
|
|
28
|
-
|
|
29
|
-
npm install @ic-reactor/react @tanstack/react-query @icp-sdk/core
|
|
10
|
+
pnpm add @ic-reactor/react @icp-sdk/core @tanstack/react-query
|
|
30
11
|
|
|
31
|
-
#
|
|
32
|
-
pnpm add @
|
|
33
|
-
|
|
34
|
-
# Optional: For Internet Identity authentication
|
|
35
|
-
npm install @icp-sdk/auth
|
|
12
|
+
# Optional: Internet Identity login helpers
|
|
13
|
+
pnpm add @icp-sdk/auth
|
|
36
14
|
```
|
|
37
15
|
|
|
38
16
|
## Quick Start
|
|
39
17
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
18
|
+
```tsx
|
|
43
19
|
// src/reactor.ts
|
|
44
|
-
import { ClientManager, Reactor } from "@ic-reactor/react"
|
|
20
|
+
import { ClientManager, Reactor, createActorHooks } from "@ic-reactor/react"
|
|
45
21
|
import { QueryClient } from "@tanstack/react-query"
|
|
46
|
-
import { idlFactory, type _SERVICE } from "./declarations/
|
|
22
|
+
import { idlFactory, type _SERVICE } from "./declarations/backend"
|
|
47
23
|
|
|
48
|
-
// Create query client for caching
|
|
49
24
|
export const queryClient = new QueryClient()
|
|
50
25
|
|
|
51
|
-
// Create client manager (handles identity and agent)
|
|
52
|
-
// Create client manager (handles identity and agent)
|
|
53
26
|
export const clientManager = new ClientManager({
|
|
54
27
|
queryClient,
|
|
55
|
-
withCanisterEnv: true,
|
|
28
|
+
withCanisterEnv: true,
|
|
56
29
|
})
|
|
57
30
|
|
|
58
|
-
// Create reactor for your canister
|
|
59
31
|
export const backend = new Reactor<_SERVICE>({
|
|
60
32
|
clientManager,
|
|
61
33
|
idlFactory,
|
|
62
|
-
name: "backend",
|
|
34
|
+
name: "backend",
|
|
63
35
|
})
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### 2. Create Hooks
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
// src/hooks.ts
|
|
70
|
-
import { createActorHooks, createAuthHooks } from "@ic-reactor/react"
|
|
71
|
-
import { backend, clientManager } from "./reactor"
|
|
72
|
-
|
|
73
|
-
// Create actor hooks for queries and mutations
|
|
74
|
-
export const { useActorQuery, useActorMutation, useActorSuspenseQuery } =
|
|
75
|
-
createActorHooks(backend)
|
|
76
36
|
|
|
77
|
-
|
|
78
|
-
|
|
37
|
+
export const {
|
|
38
|
+
useActorQuery,
|
|
39
|
+
useActorMutation,
|
|
40
|
+
useActorSuspenseQuery,
|
|
41
|
+
useActorMethod,
|
|
42
|
+
} = createActorHooks(backend)
|
|
79
43
|
```
|
|
80
44
|
|
|
81
|
-
### 3. Setup Provider (not required) and Use in Components
|
|
82
|
-
|
|
83
45
|
```tsx
|
|
84
46
|
// src/App.tsx
|
|
85
47
|
import { QueryClientProvider } from "@tanstack/react-query"
|
|
86
|
-
import { queryClient } from "./reactor"
|
|
87
|
-
import { useAuth, useActorQuery, useActorMutation } from "./hooks"
|
|
88
|
-
|
|
89
|
-
function App() {
|
|
90
|
-
return (
|
|
91
|
-
<QueryClientProvider client={queryClient}>
|
|
92
|
-
<AuthButton />
|
|
93
|
-
<Greeting />
|
|
94
|
-
</QueryClientProvider>
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function AuthButton() {
|
|
99
|
-
const { login, logout, isAuthenticated, principal } = useAuth()
|
|
100
|
-
|
|
101
|
-
return isAuthenticated ? (
|
|
102
|
-
<button onClick={() => logout()}>
|
|
103
|
-
Logout {principal?.toText().slice(0, 8)}...
|
|
104
|
-
</button>
|
|
105
|
-
) : (
|
|
106
|
-
<button onClick={() => login()}>Login with Internet Identity</button>
|
|
107
|
-
)
|
|
108
|
-
}
|
|
48
|
+
import { queryClient, useActorMethod, useActorQuery } from "./reactor"
|
|
109
49
|
|
|
110
50
|
function Greeting() {
|
|
111
|
-
|
|
112
|
-
const { data, isPending, error } = useActorQuery({
|
|
51
|
+
const { data, isPending } = useActorQuery({
|
|
113
52
|
functionName: "greet",
|
|
114
53
|
args: ["World"],
|
|
115
54
|
})
|
|
116
55
|
|
|
117
|
-
if (isPending) return <
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return <h1>{data}</h1>
|
|
56
|
+
if (isPending) return <p>Loading...</p>
|
|
57
|
+
return <p>{data}</p>
|
|
121
58
|
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Core Concepts
|
|
125
59
|
|
|
126
|
-
|
|
60
|
+
function Increment() {
|
|
61
|
+
const { call, isPending } = useActorMethod({ functionName: "increment" })
|
|
127
62
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
| Result | Unwrapped | Unwrapped |
|
|
135
|
-
| Form-friendly | No | Yes |
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
import { DisplayReactor } from "@ic-reactor/react"
|
|
139
|
-
|
|
140
|
-
// DisplayReactor for form-friendly UI work
|
|
141
|
-
const backend = new DisplayReactor<_SERVICE>({
|
|
142
|
-
clientManager,
|
|
143
|
-
idlFactory,
|
|
144
|
-
canisterId: "rrkah-fqaaa-aaaaa-aaaaq-cai",
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
// Now hooks return strings instead of bigint/Principal
|
|
148
|
-
const { data } = useActorQuery({
|
|
149
|
-
functionName: "icrc1_balance_of",
|
|
150
|
-
args: [{ owner: "aaaaa-aa", subaccount: [] }], // strings!
|
|
151
|
-
})
|
|
152
|
-
// data is "100000000" instead of 100000000n
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## Hooks Reference
|
|
156
|
-
|
|
157
|
-
### Actor Hooks (from `createActorHooks`)
|
|
158
|
-
|
|
159
|
-
| Hook | Description |
|
|
160
|
-
| ------------------------------- | ---------------------------------------------- |
|
|
161
|
-
| `useActorQuery` | Standard queries with loading states |
|
|
162
|
-
| `useActorSuspenseQuery` | Suspense-enabled queries (data always defined) |
|
|
163
|
-
| `useActorInfiniteQuery` | Paginated/infinite scroll queries |
|
|
164
|
-
| `useActorSuspenseInfiniteQuery` | Suspense infinite queries |
|
|
165
|
-
| `useActorMutation` | State-changing operations |
|
|
166
|
-
|
|
167
|
-
### Auth Hooks (from `createAuthHooks`)
|
|
168
|
-
|
|
169
|
-
| Hook | Description |
|
|
170
|
-
| ------------------ | ----------------------------------- |
|
|
171
|
-
| `useAuth` | Login, logout, authentication state |
|
|
172
|
-
| `useAgentState` | Agent initialization state |
|
|
173
|
-
| `useUserPrincipal` | Current user's Principal |
|
|
174
|
-
|
|
175
|
-
## Query Examples
|
|
176
|
-
|
|
177
|
-
### Standard Query
|
|
178
|
-
|
|
179
|
-
```tsx
|
|
180
|
-
const { data, isPending, error } = useActorQuery({
|
|
181
|
-
functionName: "get_user",
|
|
182
|
-
args: ["user-123"],
|
|
183
|
-
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
184
|
-
})
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Suspense Query
|
|
188
|
-
|
|
189
|
-
```tsx
|
|
190
|
-
// Parent must have <Suspense> boundary
|
|
191
|
-
function UserProfile() {
|
|
192
|
-
// data is never undefined with suspense!
|
|
193
|
-
const { data } = useActorSuspenseQuery({
|
|
194
|
-
functionName: "get_user",
|
|
195
|
-
args: ["user-123"],
|
|
196
|
-
})
|
|
63
|
+
return (
|
|
64
|
+
<button disabled={isPending} onClick={() => call([])}>
|
|
65
|
+
{isPending ? "Updating..." : "Increment"}
|
|
66
|
+
</button>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
197
69
|
|
|
198
|
-
|
|
70
|
+
export function App() {
|
|
71
|
+
return (
|
|
72
|
+
<QueryClientProvider client={queryClient}>
|
|
73
|
+
<Greeting />
|
|
74
|
+
<Increment />
|
|
75
|
+
</QueryClientProvider>
|
|
76
|
+
)
|
|
199
77
|
}
|
|
200
78
|
```
|
|
201
79
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
80
|
+
## Main APIs
|
|
81
|
+
|
|
82
|
+
- `createActorHooks(reactor)` for per-canister hooks like `useActorQuery` and
|
|
83
|
+
`useActorMutation`
|
|
84
|
+
- `createAuthHooks(clientManager)` for `useAuth`, `useAuthState`,
|
|
85
|
+
`useAgentState`, and `useUserPrincipal`
|
|
86
|
+
- direct reactor hooks like `useReactorQuery` when you want to pass the reactor
|
|
87
|
+
instance at call time
|
|
88
|
+
- factory helpers like `createQuery`, `createSuspenseQuery`,
|
|
89
|
+
`createInfiniteQuery`, `createSuspenseInfiniteQuery`, and `createMutation`
|
|
90
|
+
when the same operation must work both inside and outside React
|
|
91
|
+
|
|
92
|
+
## Choosing the Right Pattern
|
|
93
|
+
|
|
94
|
+
- Use `createActorHooks` for the simplest component-first integration.
|
|
95
|
+
- Use query and mutation factories when you also need loader, action, service,
|
|
96
|
+
or test usage through `.fetch()`, `.execute()`, `.invalidate()`, or
|
|
97
|
+
`.getCacheData()`.
|
|
98
|
+
- Use `DisplayReactor` when you want UI-friendly values such as strings instead
|
|
99
|
+
of `bigint` or `Principal`.
|
|
100
|
+
- Use generated hooks from `@ic-reactor/vite-plugin` or `@ic-reactor/cli` when
|
|
101
|
+
you have larger canisters or frequent `.did` changes.
|
|
102
|
+
|
|
103
|
+
## Factory Example
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { createSuspenseQueryFactory, createMutation } from "@ic-reactor/react"
|
|
107
|
+
import { backend } from "./reactor"
|
|
108
|
+
|
|
109
|
+
export const getProfile = createSuspenseQueryFactory(backend, {
|
|
110
|
+
functionName: "get_profile",
|
|
210
111
|
})
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
`createInfiniteQuery(...)` and `createInfiniteQueryFactory(...)` support standard
|
|
214
|
-
TanStack Query infinite-query options at the create level, including
|
|
215
|
-
`refetchInterval`, `refetchOnMount`, `refetchOnWindowFocus`, `retry`, and `gcTime`.
|
|
216
112
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
### Basic Mutation
|
|
220
|
-
|
|
221
|
-
```tsx
|
|
222
|
-
const { mutate, isPending, error } = useActorMutation({
|
|
113
|
+
export const updateProfile = createMutation(backend, {
|
|
223
114
|
functionName: "update_profile",
|
|
224
|
-
onSuccess: (result) => {
|
|
225
|
-
console.log("Profile updated!", result)
|
|
226
|
-
},
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
// Call the mutation
|
|
230
|
-
mutate([{ name: "Alice", bio: "Hello IC!" }])
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
## Query Factories
|
|
234
|
-
|
|
235
|
-
Create reusable query configurations with factory functions:
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
import {
|
|
239
|
-
createQuery,
|
|
240
|
-
createSuspenseQuery,
|
|
241
|
-
createMutation,
|
|
242
|
-
} from "@ic-reactor/react"
|
|
243
|
-
|
|
244
|
-
// Static query (no args at call time)
|
|
245
|
-
export const tokenNameQuery = createSuspenseQuery(backend, {
|
|
246
|
-
functionName: "icrc1_name",
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
// In component:
|
|
250
|
-
const { data } = tokenNameQuery.useSuspenseQuery()
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### Factory with Dynamic Args
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
import { createSuspenseQueryFactory } from "@ic-reactor/react"
|
|
257
|
-
|
|
258
|
-
// Factory for balance queries
|
|
259
|
-
export const getBalance = createSuspenseQueryFactory(backend, {
|
|
260
|
-
functionName: "icrc1_balance_of",
|
|
261
|
-
select: (balance) => `${balance} tokens`,
|
|
262
115
|
})
|
|
263
|
-
|
|
264
|
-
// In component - create the query instance with args at call time
|
|
265
|
-
const balanceQuery = getBalance([{ owner: userPrincipal, subaccount: [] }])
|
|
266
|
-
const { data } = balanceQuery.useSuspenseQuery()
|
|
267
116
|
```
|
|
268
117
|
|
|
269
|
-
### Infinite Query Factory (Route/Search Params Safe)
|
|
270
|
-
|
|
271
|
-
Use `getKeyArgs` in the factory config to derive a stable logical identity from
|
|
272
|
-
the first-page args, and keep pagination cursors inside `getArgs(pageParam)`.
|
|
273
|
-
This prevents cache collisions when loaders rerun with different search params.
|
|
274
|
-
|
|
275
118
|
```tsx
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
type TodoSearch = {
|
|
279
|
-
filter: "all" | "active" | "completed"
|
|
280
|
-
q: string
|
|
281
|
-
sort: "newest" | "oldest"
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
export const makeTodoListQuery = createInfiniteQueryFactory(todoReactor, {
|
|
285
|
-
functionName: "list_todos",
|
|
286
|
-
initialPageParam: 0,
|
|
287
|
-
getKeyArgs: (args) => {
|
|
288
|
-
const [request] = args
|
|
289
|
-
return [
|
|
290
|
-
{
|
|
291
|
-
filter: request.filter,
|
|
292
|
-
q: request.q,
|
|
293
|
-
sort: request.sort,
|
|
294
|
-
},
|
|
295
|
-
]
|
|
296
|
-
},
|
|
297
|
-
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
// TanStack Router loader/search-param flow
|
|
301
|
-
export async function loader({ context, deps }: any) {
|
|
302
|
-
const search = deps.search as TodoSearch
|
|
303
|
-
|
|
304
|
-
const todosQuery = makeTodoListQuery((cursor) => [
|
|
305
|
-
{
|
|
306
|
-
cursor,
|
|
307
|
-
limit: 20,
|
|
308
|
-
filter: search.filter,
|
|
309
|
-
q: search.q,
|
|
310
|
-
sort: search.sort,
|
|
311
|
-
},
|
|
312
|
-
])
|
|
313
|
-
|
|
314
|
-
await todosQuery.fetch()
|
|
315
|
-
return { queryKey: todosQuery.getQueryKey() }
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
function TodosPage({ search }: { search: TodoSearch }) {
|
|
319
|
-
const todosQuery = makeTodoListQuery((cursor) => [
|
|
320
|
-
{
|
|
321
|
-
cursor,
|
|
322
|
-
limit: 20,
|
|
323
|
-
filter: search.filter,
|
|
324
|
-
q: search.q,
|
|
325
|
-
sort: search.sort,
|
|
326
|
-
},
|
|
327
|
-
])
|
|
328
|
-
|
|
329
|
-
const { data, fetchNextPage, hasNextPage } = todosQuery.useInfiniteQuery()
|
|
330
|
-
return null
|
|
331
|
-
}
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
## Advanced: Direct Reactor Usage
|
|
335
|
-
|
|
336
|
-
Access reactor methods directly for manual cache management:
|
|
119
|
+
const profileQuery = getProfile(["alice"])
|
|
120
|
+
const { data } = profileQuery.useSuspenseQuery()
|
|
337
121
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
await backend.fetchQuery({
|
|
341
|
-
functionName: "get_user",
|
|
342
|
-
args: ["user-123"],
|
|
343
|
-
})
|
|
344
|
-
|
|
345
|
-
// Get cached data (no fetch)
|
|
346
|
-
const cached = backend.getQueryData({
|
|
347
|
-
functionName: "get_user",
|
|
348
|
-
args: ["user-123"],
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
// Invalidate cache to trigger refetch
|
|
352
|
-
backend.invalidateQueries({
|
|
353
|
-
functionName: "get_user",
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
// Direct call without caching
|
|
357
|
-
const result = await backend.callMethod({
|
|
358
|
-
functionName: "update_user",
|
|
359
|
-
args: [{ name: "Alice" }],
|
|
122
|
+
const mutation = updateProfile.useMutation({
|
|
123
|
+
invalidateQueries: [profileQuery.getQueryKey()],
|
|
360
124
|
})
|
|
361
125
|
```
|
|
362
126
|
|
|
363
127
|
## Re-exports
|
|
364
128
|
|
|
365
|
-
`@ic-reactor/react` re-exports
|
|
366
|
-
|
|
367
|
-
```typescript
|
|
368
|
-
// Everything from one package
|
|
369
|
-
import {
|
|
370
|
-
ClientManager,
|
|
371
|
-
Reactor,
|
|
372
|
-
DisplayReactor,
|
|
373
|
-
createActorHooks,
|
|
374
|
-
createAuthHooks,
|
|
375
|
-
createQuery,
|
|
376
|
-
CanisterError,
|
|
377
|
-
} from "@ic-reactor/react"
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
## Documentation
|
|
129
|
+
`@ic-reactor/react` re-exports the core runtime, so you can import these from a
|
|
130
|
+
single package:
|
|
381
131
|
|
|
382
|
-
|
|
132
|
+
- `ClientManager`
|
|
133
|
+
- `Reactor`
|
|
134
|
+
- `DisplayReactor`
|
|
135
|
+
- `CallError`
|
|
136
|
+
- `CanisterError`
|
|
137
|
+
- `ValidationError`
|
|
383
138
|
|
|
384
|
-
##
|
|
139
|
+
## See Also
|
|
385
140
|
|
|
386
|
-
|
|
141
|
+
- Docs: https://ic-reactor.b3pay.net/v3/packages/react
|
|
142
|
+
- `@ic-reactor/core`: ../core/README.md
|
|
143
|
+
- `@ic-reactor/vite-plugin`: ../vite-plugin/README.md
|
|
144
|
+
- `@ic-reactor/cli`: ../cli/README.md
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ic-reactor/react",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"description": "IC Reactor React Library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"author": "Behrad Deylami",
|
|
43
43
|
"license": "MIT",
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ic-reactor/core": "^3.1.
|
|
45
|
+
"@ic-reactor/core": "^3.1.3"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"react": ">=18.0.0",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@icp-sdk/auth": "^5.0.0",
|
|
54
54
|
"@icp-sdk/core": "^5.0.0",
|
|
55
|
-
"@size-limit/preset-small-lib": "^12.0.
|
|
55
|
+
"@size-limit/preset-small-lib": "^12.0.1",
|
|
56
56
|
"@tanstack/react-query": "^5.90",
|
|
57
57
|
"@testing-library/dom": "^10.4.1",
|
|
58
58
|
"@testing-library/jest-dom": "^6.9.1",
|
|
@@ -60,11 +60,11 @@
|
|
|
60
60
|
"@types/react": "^19.2.14",
|
|
61
61
|
"@types/react-dom": "^19.2.3",
|
|
62
62
|
"fake-indexeddb": "^6.2.5",
|
|
63
|
-
"jsdom": "^
|
|
63
|
+
"jsdom": "^29.0.0",
|
|
64
64
|
"react": "^19.2.3",
|
|
65
65
|
"react-dom": "^19.2.3",
|
|
66
|
-
"size-limit": "^12.0.
|
|
67
|
-
"vitest": "^4.0
|
|
66
|
+
"size-limit": "^12.0.1",
|
|
67
|
+
"vitest": "^4.1.0"
|
|
68
68
|
},
|
|
69
69
|
"size-limit": [
|
|
70
70
|
{
|