@ic-reactor/react 3.7.0 → 3.8.0

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 (86) hide show
  1. package/README.md +93 -9
  2. package/dist/auth/authentication-manager.d.ts +37 -5
  3. package/dist/auth/authentication-manager.d.ts.map +1 -1
  4. package/dist/auth/authentication-manager.js +111 -37
  5. package/dist/auth/authentication-manager.js.map +1 -1
  6. package/dist/auth/createIdentityAttributeHooks.d.ts +2 -2
  7. package/dist/auth/createIdentityAttributeHooks.d.ts.map +1 -1
  8. package/dist/auth/identity-attributes-manager.d.ts +12 -5
  9. package/dist/auth/identity-attributes-manager.d.ts.map +1 -1
  10. package/dist/auth/identity-attributes-manager.js +42 -28
  11. package/dist/auth/identity-attributes-manager.js.map +1 -1
  12. package/dist/auth/identity-attributes.d.ts +1 -1
  13. package/dist/auth/identity-attributes.d.ts.map +1 -1
  14. package/dist/auth/identity-attributes.js +1 -1
  15. package/dist/auth/identity-attributes.js.map +1 -1
  16. package/dist/auth/index.d.ts +7 -7
  17. package/dist/auth/index.d.ts.map +1 -1
  18. package/dist/auth/index.js +7 -7
  19. package/dist/auth/index.js.map +1 -1
  20. package/dist/auth/types.d.ts +123 -16
  21. package/dist/auth/types.d.ts.map +1 -1
  22. package/dist/createActorHooks.d.ts +4 -4
  23. package/dist/createActorHooks.d.ts.map +1 -1
  24. package/dist/createActorHooks.js +6 -6
  25. package/dist/createActorHooks.js.map +1 -1
  26. package/dist/createInfiniteQuery.d.ts +1 -1
  27. package/dist/createInfiniteQuery.d.ts.map +1 -1
  28. package/dist/createInfiniteQuery.js +1 -1
  29. package/dist/createInfiniteQuery.js.map +1 -1
  30. package/dist/createMutation.d.ts +1 -1
  31. package/dist/createMutation.d.ts.map +1 -1
  32. package/dist/createQuery.d.ts +1 -1
  33. package/dist/createQuery.d.ts.map +1 -1
  34. package/dist/createQuery.js +1 -1
  35. package/dist/createQuery.js.map +1 -1
  36. package/dist/createSuspenseInfiniteQuery.d.ts +1 -1
  37. package/dist/createSuspenseInfiniteQuery.d.ts.map +1 -1
  38. package/dist/createSuspenseInfiniteQuery.js +1 -1
  39. package/dist/createSuspenseInfiniteQuery.js.map +1 -1
  40. package/dist/createSuspenseQuery.d.ts +1 -1
  41. package/dist/createSuspenseQuery.d.ts.map +1 -1
  42. package/dist/createSuspenseQuery.js +1 -1
  43. package/dist/createSuspenseQuery.js.map +1 -1
  44. package/dist/defineReactor.d.ts +54 -4
  45. package/dist/defineReactor.d.ts.map +1 -1
  46. package/dist/defineReactor.js +77 -7
  47. package/dist/defineReactor.js.map +1 -1
  48. package/dist/hooks/createAuthHooks.d.ts +2 -2
  49. package/dist/hooks/createAuthHooks.d.ts.map +1 -1
  50. package/dist/hooks/createAuthHooks.js +7 -2
  51. package/dist/hooks/createAuthHooks.js.map +1 -1
  52. package/dist/hooks/useActorInfiniteQuery.js +1 -1
  53. package/dist/hooks/useActorInfiniteQuery.js.map +1 -1
  54. package/dist/hooks/useActorSuspenseInfiniteQuery.js +1 -1
  55. package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +1 -1
  56. package/dist/index.d.ts +11 -11
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +11 -11
  59. package/dist/index.js.map +1 -1
  60. package/llms.txt +1 -1
  61. package/package.json +14 -9
  62. package/src/auth/authentication-manager.ts +121 -49
  63. package/src/auth/createIdentityAttributeHooks.ts +2 -2
  64. package/src/auth/identity-attributes-manager.ts +53 -44
  65. package/src/auth/identity-attributes.ts +2 -2
  66. package/src/auth/index.ts +7 -7
  67. package/src/auth/types.ts +134 -18
  68. package/src/createActorHooks.ts +9 -9
  69. package/src/createInfiniteQuery.ts +2 -2
  70. package/src/createMutation.ts +1 -1
  71. package/src/createQuery.ts +2 -2
  72. package/src/createSuspenseInfiniteQuery.ts +2 -2
  73. package/src/createSuspenseQuery.ts +2 -2
  74. package/src/defineReactor.ts +136 -14
  75. package/src/hooks/createAuthHooks.ts +8 -3
  76. package/src/hooks/useActorInfiniteQuery.ts +1 -1
  77. package/src/hooks/useActorSuspenseInfiniteQuery.ts +1 -1
  78. package/src/index.ts +11 -11
  79. package/src/defineReactor.test.ts +0 -70
  80. package/src/hooks/useActorInfiniteQuery.test.tsx +0 -457
  81. package/src/hooks/useActorMethod.test.tsx +0 -798
  82. package/src/hooks/useActorMutation.test.tsx +0 -220
  83. package/src/hooks/useActorQuery.test.tsx +0 -287
  84. package/src/hooks/useActorSuspenseInfiniteQuery.test.tsx +0 -472
  85. package/src/hooks/useActorSuspenseQuery.test.tsx +0 -254
  86. package/src/utils.test.ts +0 -14
@@ -1,220 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest"
2
- import { renderHook } from "@testing-library/react"
3
- import React from "react"
4
- import { ClientManager, Reactor } from "@ic-reactor/core"
5
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
6
- import { Actor, ActorMethod } from "@icp-sdk/core/agent"
7
- import { useActorMutation } from "./useActorMutation"
8
-
9
- // Mock IDL factory
10
- const idlFactory = ({ IDL }: any) => {
11
- return IDL.Service({
12
- create_user: IDL.Func(
13
- [IDL.Record({ name: IDL.Text })],
14
- [IDL.Record({ id: IDL.Text, name: IDL.Text })],
15
- ["update"]
16
- ),
17
- update_user: IDL.Func(
18
- [IDL.Record({ id: IDL.Text, name: IDL.Text })],
19
- [IDL.Record({ id: IDL.Text, name: IDL.Text })],
20
- ["update"]
21
- ),
22
- delete_user: IDL.Func([IDL.Text], [IDL.Bool], ["update"]),
23
- })
24
- }
25
-
26
- // Define Actor Interface
27
- interface CreateUserInput {
28
- name: string
29
- }
30
-
31
- interface UpdateUserInput {
32
- id: string
33
- name: string
34
- }
35
-
36
- interface User {
37
- id: string
38
- name: string
39
- }
40
-
41
- // Actor type with methods
42
- interface TestActor {
43
- get_user: ActorMethod<[string], User>
44
- create_user: ActorMethod<[CreateUserInput], User>
45
- update_user: ActorMethod<[UpdateUserInput], User>
46
- delete_user: ActorMethod<[string], boolean>
47
- }
48
-
49
- // Mock data
50
- const mockUserCreated: User = { id: "user-1", name: "Alice" }
51
- const mockUserUpdated: User = { id: "user-1", name: "Bob" }
52
-
53
- // Mock Actor.createActor
54
- vi.mock("@icp-sdk/core/agent", async () => {
55
- const actual = await vi.importActual<typeof import("@icp-sdk/core/agent")>(
56
- "@icp-sdk/core/agent"
57
- )
58
- return {
59
- ...actual,
60
- Actor: class extends actual.Actor {
61
- static createActor = vi.fn()
62
- static canisterIdOf = vi.fn().mockReturnValue({
63
- toString: () => "test-canister-id",
64
- })
65
- static interfaceOf = vi.fn().mockReturnValue({
66
- _fields: [],
67
- })
68
- },
69
- }
70
- })
71
-
72
- describe("useActorMutation", () => {
73
- let queryClient: QueryClient
74
- let clientManager: ClientManager
75
- let mockActor: TestActor
76
- let reactor: Reactor<TestActor>
77
-
78
- beforeEach(() => {
79
- queryClient = new QueryClient({
80
- defaultOptions: {
81
- mutations: {
82
- retry: false,
83
- },
84
- },
85
- })
86
-
87
- clientManager = new ClientManager({ queryClient })
88
-
89
- // Setup mock actor
90
- mockActor = {
91
- create_user: vi.fn().mockResolvedValue(mockUserCreated),
92
- update_user: vi.fn().mockResolvedValue(mockUserUpdated),
93
- delete_user: vi.fn().mockResolvedValue(true),
94
- } as unknown as TestActor
95
- ;(Actor.createActor as any).mockReturnValue(mockActor)
96
-
97
- reactor = new Reactor<TestActor>({
98
- clientManager,
99
- canisterId: "rrkah-fqaaa-aaaaa-aaaaq-cai",
100
- idlFactory,
101
- name: "test",
102
- })
103
- })
104
-
105
- const wrapper = ({ children }: { children: React.ReactNode }) => (
106
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
107
- )
108
-
109
- describe("basic functionality", () => {
110
- it("should create a mutation hook", () => {
111
- const { result } = renderHook(
112
- () =>
113
- useActorMutation({
114
- reactor,
115
- functionName: "create_user",
116
- }),
117
- { wrapper }
118
- )
119
-
120
- expect(result.current).toBeDefined()
121
- })
122
-
123
- it("should return correct hook structure", () => {
124
- const { result } = renderHook(
125
- () =>
126
- useActorMutation({
127
- reactor,
128
- functionName: "create_user",
129
- }),
130
- { wrapper }
131
- )
132
-
133
- expect(result.current.mutate).toBeInstanceOf(Function)
134
- expect(result.current.mutateAsync).toBeInstanceOf(Function)
135
- expect(typeof result.current.isPending).toBe("boolean")
136
- expect(typeof result.current.isSuccess).toBe("boolean")
137
- expect(typeof result.current.isError).toBe("boolean")
138
- })
139
-
140
- it("should have correct initial state", () => {
141
- const { result } = renderHook(
142
- () =>
143
- useActorMutation({
144
- reactor,
145
- functionName: "create_user",
146
- }),
147
- { wrapper }
148
- )
149
-
150
- expect(result.current.isPending).toBe(false)
151
- expect(result.current.isSuccess).toBe(false)
152
- expect(result.current.isError).toBe(false)
153
- expect(result.current.data).toBeUndefined()
154
- })
155
- })
156
-
157
- describe("hook options", () => {
158
- it("should accept mutation options like onSuccess and onError", () => {
159
- const onSuccess = vi.fn()
160
- const onError = vi.fn()
161
-
162
- const { result } = renderHook(
163
- () =>
164
- useActorMutation({
165
- reactor,
166
- functionName: "create_user",
167
- onSuccess,
168
- onError,
169
- }),
170
- { wrapper }
171
- )
172
-
173
- expect(result.current.mutate).toBeInstanceOf(Function)
174
- })
175
-
176
- it("should expose mutate and mutateAsync methods", () => {
177
- const { result } = renderHook(
178
- () =>
179
- useActorMutation({
180
- reactor,
181
- functionName: "create_user",
182
- }),
183
- { wrapper }
184
- )
185
-
186
- expect(result.current.mutate).toBeInstanceOf(Function)
187
- expect(result.current.mutateAsync).toBeInstanceOf(Function)
188
- })
189
- })
190
-
191
- describe("invalidateQueries functionality", () => {
192
- it("should accept invalidateQueries option", () => {
193
- const { result } = renderHook(
194
- () =>
195
- useActorMutation({
196
- reactor,
197
- functionName: "update_user",
198
- invalidateQueries: [["test-canister", "get_user"]],
199
- }),
200
- { wrapper }
201
- )
202
-
203
- expect(result.current.mutate).toBeInstanceOf(Function)
204
- })
205
-
206
- it("should support invalidateQueries with args", () => {
207
- const { result } = renderHook(
208
- () =>
209
- useActorMutation({
210
- reactor,
211
- functionName: "update_user",
212
- invalidateQueries: [["test-canister", "get_user", "user-1"]],
213
- }),
214
- { wrapper }
215
- )
216
-
217
- expect(result.current.mutate).toBeInstanceOf(Function)
218
- })
219
- })
220
- })
@@ -1,287 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest"
2
- import { renderHook, waitFor } from "@testing-library/react"
3
- import React from "react"
4
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
5
- import { useActorQuery } from "./useActorQuery"
6
- import { ActorMethod } from "@icp-sdk/core/agent"
7
- import { Reactor } from "@ic-reactor/core"
8
-
9
- // Define a test actor type
10
- type TestActor = {
11
- greet: ActorMethod<[], string>
12
- greetWithName: ActorMethod<[string], string>
13
- getCount: ActorMethod<[], bigint>
14
- }
15
-
16
- // Mock Reactor
17
- const createMockReactor = (queryClient: QueryClient): Reactor<TestActor> =>
18
- ({
19
- queryClient,
20
- getQueryOptions: vi.fn().mockImplementation(({ functionName, args }) => ({
21
- queryKey: ["test-canister", functionName, ...(args || [])],
22
- queryFn: vi.fn().mockImplementation(async () => {
23
- if (functionName === "greet") return "Hello, World!"
24
- if (functionName === "greetWithName")
25
- return `Hello, ${args?.[0] || "Guest"}!`
26
- if (functionName === "getCount") return BigInt(42)
27
- return null
28
- }),
29
- })),
30
- }) as unknown as Reactor<TestActor>
31
-
32
- describe("useActorQuery", () => {
33
- let queryClient: QueryClient
34
- let mockReactor: Reactor<TestActor>
35
-
36
- beforeEach(() => {
37
- queryClient = new QueryClient({
38
- defaultOptions: {
39
- queries: {
40
- retry: false,
41
- },
42
- },
43
- })
44
- mockReactor = createMockReactor(queryClient)
45
- })
46
-
47
- const wrapper = ({ children }: { children: React.ReactNode }) => (
48
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
49
- )
50
-
51
- describe("basic functionality", () => {
52
- it("should fetch data without select", async () => {
53
- const { result } = renderHook(
54
- () =>
55
- useActorQuery<TestActor, "greet">({
56
- reactor: mockReactor,
57
- functionName: "greet",
58
- }),
59
- { wrapper }
60
- )
61
-
62
- await waitFor(() => {
63
- expect(result.current.isSuccess).toBe(true)
64
- })
65
-
66
- expect(result.current.data).toBe("Hello, World!")
67
- })
68
-
69
- it("should pass args to the query", async () => {
70
- const { result } = renderHook(
71
- () =>
72
- useActorQuery<TestActor, "greetWithName">({
73
- reactor: mockReactor,
74
- functionName: "greetWithName",
75
- args: ["Alice"],
76
- }),
77
- { wrapper }
78
- )
79
-
80
- await waitFor(() => {
81
- expect(result.current.isSuccess).toBe(true)
82
- })
83
-
84
- expect(result.current.data).toBe("Hello, Alice!")
85
- expect(mockReactor.getQueryOptions).toHaveBeenCalledWith({
86
- callConfig: undefined,
87
- functionName: "greetWithName",
88
- args: ["Alice"],
89
- })
90
- })
91
-
92
- it("should handle bigint return types", async () => {
93
- const { result } = renderHook(
94
- () =>
95
- useActorQuery<TestActor, "getCount">({
96
- reactor: mockReactor,
97
- functionName: "getCount",
98
- }),
99
- { wrapper }
100
- )
101
-
102
- await waitFor(() => {
103
- expect(result.current.isSuccess).toBe(true)
104
- })
105
-
106
- expect(result.current.data).toBe(BigInt(42))
107
- })
108
- })
109
-
110
- describe("select function", () => {
111
- it("should transform data with select function", async () => {
112
- const { result } = renderHook(
113
- () =>
114
- useActorQuery<TestActor, "greet", "candid", number>({
115
- reactor: mockReactor,
116
- functionName: "greet",
117
- select: (data: string) => data.length,
118
- }),
119
- { wrapper }
120
- )
121
-
122
- await waitFor(() => {
123
- expect(result.current.isSuccess).toBe(true)
124
- })
125
-
126
- // "Hello, World!" has 13 characters
127
- expect(result.current.data).toBe(13)
128
- })
129
-
130
- it("should transform data to different type with select", async () => {
131
- const { result } = renderHook(
132
- () =>
133
- useActorQuery<TestActor, "greet", "candid", { message: string }>({
134
- reactor: mockReactor,
135
- functionName: "greet",
136
- select: (data: string) => ({ message: data }),
137
- }),
138
- { wrapper }
139
- )
140
-
141
- await waitFor(() => {
142
- expect(result.current.isSuccess).toBe(true)
143
- })
144
-
145
- expect(result.current.data).toEqual({ message: "Hello, World!" })
146
- })
147
-
148
- it("should transform bigint to number with select", async () => {
149
- const { result } = renderHook(
150
- () =>
151
- useActorQuery<TestActor, "getCount", "candid", number>({
152
- reactor: mockReactor,
153
- functionName: "getCount",
154
- select: (data: bigint) => Number(data),
155
- }),
156
- { wrapper }
157
- )
158
-
159
- await waitFor(() => {
160
- expect(result.current.isSuccess).toBe(true)
161
- })
162
-
163
- expect(result.current.data).toBe(42)
164
- expect(typeof result.current.data).toBe("number")
165
- })
166
-
167
- it("should work with array transformation in select", async () => {
168
- const { result } = renderHook(
169
- () =>
170
- useActorQuery<TestActor, "greet", "candid", string[]>({
171
- reactor: mockReactor,
172
- functionName: "greet",
173
- select: (data: string) => data.split(", "),
174
- }),
175
- { wrapper }
176
- )
177
-
178
- await waitFor(() => {
179
- expect(result.current.isSuccess).toBe(true)
180
- })
181
-
182
- expect(result.current.data).toEqual(["Hello", "World!"])
183
- })
184
- })
185
-
186
- describe("query options", () => {
187
- it("should respect enabled: false option", async () => {
188
- const { result } = renderHook(
189
- () =>
190
- useActorQuery<TestActor, "greet">({
191
- reactor: mockReactor,
192
- functionName: "greet",
193
- enabled: false,
194
- }),
195
- { wrapper }
196
- )
197
-
198
- // Should stay in pending state
199
- expect(result.current.isPending).toBe(true)
200
- expect(result.current.fetchStatus).toBe("idle")
201
- expect(result.current.data).toBeUndefined()
202
- })
203
-
204
- it("should use custom staleTime", async () => {
205
- const { result } = renderHook(
206
- () =>
207
- useActorQuery<TestActor, "greet">({
208
- reactor: mockReactor,
209
- functionName: "greet",
210
- staleTime: 1000 * 60 * 10, // 10 minutes
211
- }),
212
- { wrapper }
213
- )
214
-
215
- await waitFor(() => {
216
- expect(result.current.isSuccess).toBe(true)
217
- })
218
-
219
- expect(result.current.isStale).toBe(false)
220
- })
221
- })
222
-
223
- describe("type inference", () => {
224
- it("should infer string type for greet method without select", async () => {
225
- const { result } = renderHook(
226
- () =>
227
- useActorQuery<TestActor, "greet">({
228
- reactor: mockReactor,
229
- functionName: "greet",
230
- }),
231
- { wrapper }
232
- )
233
-
234
- await waitFor(() => {
235
- expect(result.current.isSuccess).toBe(true)
236
- })
237
-
238
- // TypeScript should infer data as string
239
- const data: string | undefined = result.current.data
240
- expect(typeof data).toBe("string")
241
- })
242
-
243
- it("should infer number type when select returns number", async () => {
244
- const { result } = renderHook(
245
- () =>
246
- useActorQuery({
247
- reactor: mockReactor,
248
- functionName: "greet",
249
- select: (data: any) => data.length,
250
- }),
251
- { wrapper }
252
- )
253
-
254
- await waitFor(() => {
255
- expect(result.current.isSuccess).toBe(true)
256
- })
257
-
258
- // TypeScript should infer data as number
259
- const data: number | undefined = result.current.data
260
- expect(typeof data).toBe("number")
261
- })
262
- })
263
-
264
- describe("refetching", () => {
265
- it("should support manual refetch", async () => {
266
- const { result } = renderHook(
267
- () =>
268
- useActorQuery<TestActor, "greet">({
269
- reactor: mockReactor,
270
- functionName: "greet",
271
- }),
272
- { wrapper }
273
- )
274
-
275
- await waitFor(() => {
276
- expect(result.current.isSuccess).toBe(true)
277
- })
278
-
279
- // Refetch should be available
280
- expect(typeof result.current.refetch).toBe("function")
281
-
282
- await result.current.refetch()
283
-
284
- expect(result.current.isSuccess).toBe(true)
285
- })
286
- })
287
- })