@ic-reactor/react 1.4.4 → 1.5.1

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.
@@ -57,8 +57,7 @@ import { CreateActorContextParameters, CreateActorContextReturnType } from "./ty
57
57
  * };
58
58
  * ```
59
59
  *
60
- * This function streamlines the process of setting up a context for IC actor interactions within a React app, making it easier
61
- * to manage actor state and perform actions such as queries or updates. It abstracts away the complexities involved in directly
62
- * managing IC agents and actors, providing a simple, declarative API for developers.
60
+ * This function streamlines the process of setting up a context for IC actor interactions within a React app,
61
+ * it provides a type-safe and efficient way to manage actor state and interactions.
63
62
  */
64
63
  export declare function createActorContext<A = BaseActor>(contextConfig?: CreateActorContextParameters): CreateActorContextReturnType<A>;
@@ -75,9 +75,8 @@ const extractActorContext_1 = require("../helpers/extractActorContext");
75
75
  * };
76
76
  * ```
77
77
  *
78
- * This function streamlines the process of setting up a context for IC actor interactions within a React app, making it easier
79
- * to manage actor state and perform actions such as queries or updates. It abstracts away the complexities involved in directly
80
- * managing IC agents and actors, providing a simple, declarative API for developers.
78
+ * This function streamlines the process of setting up a context for IC actor interactions within a React app,
79
+ * it provides a type-safe and efficient way to manage actor state and interactions.
81
80
  */
82
81
  function createActorContext(contextConfig = {}) {
83
82
  const { canisterId: defaultCanisterId } = contextConfig, defaultConfig = __rest(contextConfig, ["canisterId"]);
@@ -16,8 +16,8 @@ import type { CreateAgentContextReturnType, CreateAgentCotextParameters } from "
16
16
  * Hooks extracted from the created context for managing agent and authentication state within components.
17
17
  *
18
18
  * @example
19
- * agent.ts
20
19
  * ```tsx
20
+ * // agent.ts
21
21
  * import { createAgentContext } from "@ic-reactor/react";
22
22
  * import { CreateAgentCotextParameters } from "@ic-reactor/react/dist/types";
23
23
  *
@@ -38,11 +38,11 @@ import type { CreateAgentContextReturnType, CreateAgentCotextParameters } from "
38
38
  * useAgentManager,
39
39
  * useUserPrincipal,
40
40
  * } = createAgentContext(agentConfig);
41
- *
42
- * // Now you can use the returned hooks in your React components
43
41
  *```
44
- * App.tsx
42
+ * Now you can use the returned hooks in your React components
43
+ *
45
44
  * ```tsx
45
+ * // App.tsx
46
46
  * import React from 'react';
47
47
  * import { AgentProvider } from './agent';
48
48
  *
@@ -38,8 +38,8 @@ const utils_1 = require("../utils");
38
38
  * Hooks extracted from the created context for managing agent and authentication state within components.
39
39
  *
40
40
  * @example
41
- * agent.ts
42
41
  * ```tsx
42
+ * // agent.ts
43
43
  * import { createAgentContext } from "@ic-reactor/react";
44
44
  * import { CreateAgentCotextParameters } from "@ic-reactor/react/dist/types";
45
45
  *
@@ -60,11 +60,11 @@ const utils_1 = require("../utils");
60
60
  * useAgentManager,
61
61
  * useUserPrincipal,
62
62
  * } = createAgentContext(agentConfig);
63
- *
64
- * // Now you can use the returned hooks in your React components
65
63
  *```
66
- * App.tsx
64
+ * Now you can use the returned hooks in your React components
65
+ *
67
66
  * ```tsx
67
+ * // App.tsx
68
68
  * import React from 'react';
69
69
  * import { AgentProvider } from './agent';
70
70
  *
@@ -26,5 +26,4 @@ export interface CreateActorContextParameters extends Omit<ActorManagerParameter
26
26
  didjsId?: string;
27
27
  canisterId?: string;
28
28
  idlFactory?: IDL.InterfaceFactory;
29
- loadingComponent?: React.ReactNode;
30
29
  }
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
26
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
27
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -19,13 +42,12 @@ var __rest = (this && this.__rest) || function (s, e) {
19
42
  }
20
43
  return t;
21
44
  };
22
- var __importDefault = (this && this.__importDefault) || function (mod) {
23
- return (mod && mod.__esModule) ? mod : { "default": mod };
24
- };
25
45
  Object.defineProperty(exports, "__esModule", { value: true });
26
46
  exports.actorHooks = void 0;
27
- const react_1 = __importDefault(require("react"));
47
+ const React = __importStar(require("react"));
28
48
  const zustand_1 = require("zustand");
49
+ const utils_1 = require("../utils");
50
+ const shallow_1 = require("zustand/react/shallow");
29
51
  const DEFAULT_STATE = {
30
52
  data: undefined,
31
53
  error: undefined,
@@ -47,19 +69,34 @@ const DEFAULT_STATE = {
47
69
  * Each hook is designed to simplify the process of interacting with actors in IC projects by abstracting away the complexity of state management, error handling, and method invocation.
48
70
  */
49
71
  const actorHooks = (actorManager) => {
50
- const { actorStore, canisterId, visitFunction, methodAttributes, extractMethodAttributes, extractInterface, callMethod, initialize, } = actorManager;
51
- const useActorState = () => (Object.assign(Object.assign({}, (0, zustand_1.useStore)(actorStore)), { canisterId }));
72
+ const { actorStore, canisterId, visitFunction, methodAttributes, updateMethodState, extractMethodAttributes, extractInterface, callMethod, initialize, } = actorManager;
73
+ const useActorState = () => (0, zustand_1.useStore)(actorStore, (0, shallow_1.useShallow)((state) => ({
74
+ error: state.error,
75
+ initialized: state.initialized,
76
+ initializing: state.initializing,
77
+ canisterId,
78
+ })));
79
+ const useMethodState = (functionName, requestKey) => {
80
+ const state = (0, zustand_1.useStore)(actorStore, (0, shallow_1.useShallow)((state) => { var _a; return (_a = state.methodState[functionName]) === null || _a === void 0 ? void 0 : _a[requestKey]; })) || DEFAULT_STATE;
81
+ const setSharedState = React.useCallback((newState) => {
82
+ updateMethodState(functionName, requestKey, newState);
83
+ }, [functionName, requestKey]);
84
+ return [state, setSharedState];
85
+ };
86
+ const useMethodAttributes = () => {
87
+ return React.useMemo(extractMethodAttributes, []);
88
+ };
52
89
  const useMethodNames = () => {
53
- return react_1.default.useMemo(() => Object.keys(extractMethodAttributes()), []);
90
+ return React.useMemo(() => Object.keys(extractMethodAttributes()), []);
54
91
  };
55
92
  const useActorInterface = () => {
56
- return react_1.default.useMemo(() => extractInterface(), []);
93
+ return React.useMemo(() => extractInterface(), []);
57
94
  };
58
95
  const useVisitService = () => {
59
96
  return visitFunction;
60
97
  };
61
98
  const useVisitMethod = (functionName) => {
62
- return react_1.default.useMemo(() => {
99
+ return React.useMemo(() => {
63
100
  if (!visitFunction[functionName]) {
64
101
  throw new Error(`Method ${functionName} not found`);
65
102
  }
@@ -68,11 +105,12 @@ const actorHooks = (actorManager) => {
68
105
  };
69
106
  const useSharedCall = (_a) => {
70
107
  var { args = [], functionName, throwOnError = false } = _a, events = __rest(_a, ["args", "functionName", "throwOnError"]);
71
- const [sharedState, setSharedState] = react_1.default.useState(DEFAULT_STATE);
72
- const reset = react_1.default.useCallback(() => setSharedState(DEFAULT_STATE), []);
73
- const call = react_1.default.useCallback((eventOrReplaceArgs) => __awaiter(void 0, void 0, void 0, function* () {
108
+ const requestKey = React.useMemo(() => (0, utils_1.generateRequestHash)(args), [args]);
109
+ const [sharedState, setSharedState] = useMethodState(functionName, requestKey);
110
+ const reset = React.useCallback(() => updateMethodState(functionName, requestKey, DEFAULT_STATE), [functionName, requestKey]);
111
+ const call = React.useCallback((eventOrReplaceArgs) => __awaiter(void 0, void 0, void 0, function* () {
74
112
  var _b, _c, _d, _e, _f;
75
- setSharedState((prev) => (Object.assign(Object.assign({}, prev), { error: undefined, loading: true })));
113
+ setSharedState({ error: undefined, loading: true });
76
114
  (_b = events === null || events === void 0 ? void 0 : events.onLoading) === null || _b === void 0 ? void 0 : _b.call(events, true);
77
115
  try {
78
116
  const replaceArgs = eventOrReplaceArgs instanceof Array ? eventOrReplaceArgs : args;
@@ -85,24 +123,27 @@ const actorHooks = (actorManager) => {
85
123
  catch (error) {
86
124
  // eslint-disable-next-line no-console
87
125
  console.error("Error in call:", error);
88
- setSharedState((prevState) => (Object.assign(Object.assign({}, prevState), { error: error, loading: false })));
126
+ setSharedState({
127
+ error: error,
128
+ loading: false,
129
+ });
89
130
  (_e = events === null || events === void 0 ? void 0 : events.onError) === null || _e === void 0 ? void 0 : _e.call(events, error);
90
131
  (_f = events === null || events === void 0 ? void 0 : events.onLoading) === null || _f === void 0 ? void 0 : _f.call(events, false);
91
132
  if (throwOnError)
92
133
  throw error;
93
134
  }
94
135
  }), [args, functionName, events]);
95
- return Object.assign({ call, reset }, sharedState);
136
+ return Object.assign({ call, reset, requestKey }, sharedState);
96
137
  };
97
138
  const useQueryCall = (_a) => {
98
139
  var { refetchOnMount = true, refetchInterval = false } = _a, rest = __rest(_a, ["refetchOnMount", "refetchInterval"]);
99
140
  const _b = useSharedCall(rest), { call } = _b, state = __rest(_b, ["call"]);
100
- const intervalId = react_1.default.useRef();
101
- react_1.default.useEffect(() => {
141
+ const intervalId = React.useRef();
142
+ React.useEffect(() => {
102
143
  if (refetchInterval) {
103
144
  intervalId.current = setInterval(call, refetchInterval);
104
145
  }
105
- if (refetchOnMount) {
146
+ if (refetchOnMount && state.data === undefined) {
106
147
  call();
107
148
  }
108
149
  return () => clearInterval(intervalId.current);
@@ -110,37 +151,61 @@ const actorHooks = (actorManager) => {
110
151
  return Object.assign({ call }, state);
111
152
  };
112
153
  const useUpdateCall = useSharedCall;
113
- const useMethod = (args) => {
114
- const visit = useVisitMethod(args.functionName);
115
- const attributes = methodAttributes[args.functionName];
116
- let refetchOnMount = args.refetchOnMount;
117
- let refetchInterval = args.refetchInterval;
154
+ const useMethod = (params) => {
155
+ const visit = React.useCallback((extractorClass, data) => {
156
+ if (!visitFunction[params.functionName]) {
157
+ throw new Error(`Method ${params.functionName} not found`);
158
+ }
159
+ return visitFunction[params.functionName](extractorClass, data);
160
+ }, [params.functionName]);
161
+ const attributes = React.useMemo(() => methodAttributes[params.functionName], [params.functionName]);
162
+ const validateArgs = React.useCallback((args, throwOnError = false) => {
163
+ if (attributes.numberOfArgs > 0) {
164
+ if (args === undefined || args.length === 0) {
165
+ if (throwOnError) {
166
+ throw new Error(`Method ${params.functionName} requires ${attributes.numberOfArgs} arguments, but none were provided.`);
167
+ }
168
+ return false;
169
+ }
170
+ try {
171
+ attributes.validate(args);
172
+ return true;
173
+ }
174
+ catch (error) {
175
+ if (throwOnError) {
176
+ throw error;
177
+ }
178
+ return false;
179
+ }
180
+ }
181
+ return true;
182
+ }, [attributes]);
183
+ let refetchOnMount = params.refetchOnMount;
184
+ let refetchInterval = params.refetchInterval;
118
185
  let formRequired = true;
119
186
  switch (attributes.type) {
120
187
  case "query":
121
- try {
122
- if (attributes.numberOfArgs > 0 && args.args === undefined) {
123
- throw new Error("Args required");
124
- }
125
- attributes.validate((args.args || []));
126
- formRequired = args.refetchOnMount === false ? true : false;
188
+ if (validateArgs(params.args)) {
189
+ formRequired = params.refetchOnMount === false ? true : false;
127
190
  }
128
- catch (error) {
191
+ else {
129
192
  refetchOnMount = false;
130
193
  refetchInterval = false;
131
194
  }
132
- return Object.assign(Object.assign({ visit }, useQueryCall(Object.assign(Object.assign({}, args), { refetchOnMount,
195
+ return Object.assign(Object.assign({ visit,
196
+ validateArgs }, useQueryCall(Object.assign(Object.assign({}, params), { refetchOnMount,
133
197
  refetchInterval }))), { formRequired });
134
198
  case "update":
135
- return Object.assign(Object.assign({ visit }, useUpdateCall(args)), { formRequired });
199
+ return Object.assign(Object.assign({ visit, validateArgs }, useUpdateCall(params)), { formRequired });
136
200
  default:
137
201
  throw new Error(`Method type ${attributes.type} not found`);
138
202
  }
139
203
  };
140
204
  return {
141
205
  initialize,
142
- useMethod,
206
+ useMethodAttributes,
143
207
  useMethodNames,
208
+ useMethod,
144
209
  useQueryCall,
145
210
  useUpdateCall,
146
211
  useActorState,
@@ -40,6 +40,7 @@ function extractActorContext(actorContext) {
40
40
  };
41
41
  const initialize = () => useActorContext().initialize();
42
42
  const useMethodNames = () => useActorContext().useMethodNames();
43
+ const useMethodAttributes = () => useActorContext().useMethodAttributes();
43
44
  const useActorState = () => useActorContext().useActorState();
44
45
  const useMethod = (args) => useActorContext().useMethod(args);
45
46
  const useQueryCall = (args) => useActorContext().useQueryCall(args);
@@ -51,6 +52,7 @@ function extractActorContext(actorContext) {
51
52
  useActorState,
52
53
  useMethod,
53
54
  useMethodNames,
55
+ useMethodAttributes,
54
56
  useQueryCall,
55
57
  useUpdateCall,
56
58
  useVisitMethod,
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import type { ServiceClass } from "@dfinity/candid/lib/cjs/idl";
3
- import type { ActorState, CanisterId, AuthClientLoginOptions, ActorMethodParameters, ActorMethodReturnType, Identity, Principal, FunctionName, VisitService, AuthState, HttpAgent, AgentState, BaseActor } from "@ic-reactor/core/dist/types";
3
+ import type { ActorState, CanisterId, AuthClientLoginOptions, ActorMethodParameters, ActorMethodReturnType, Identity, Principal, FunctionName, VisitService, AuthState, HttpAgent, AgentState, BaseActor, MethodAttributes } from "@ic-reactor/core/dist/types";
4
4
  export interface AgentHooksReturnType {
5
5
  useAgent: () => HttpAgent | undefined;
6
6
  useAgentState: () => AgentState;
@@ -55,6 +55,7 @@ export type UseSharedCallState<A, M extends FunctionName<A>> = {
55
55
  loading: boolean;
56
56
  };
57
57
  export interface UseSharedCallReturnType<A, M extends FunctionName<A> = FunctionName<A>> extends UseSharedCallState<A, M> {
58
+ requestKey: string;
58
59
  reset: () => void;
59
60
  call: (eventOrReplaceArgs?: React.MouseEvent | ActorMethodParameters<A[M]>) => Promise<ActorMethodReturnType<A[M]> | undefined>;
60
61
  }
@@ -76,8 +77,10 @@ export interface UseMethodParameters<A, M extends FunctionName<A>> extends UseQu
76
77
  export interface UseMethodReturnType<A, M extends FunctionName<A> = FunctionName<A>> {
77
78
  loading: boolean;
78
79
  formRequired: boolean;
80
+ requestKey: string;
79
81
  error: Error | undefined;
80
82
  data: ActorMethodReturnType<A[M]> | undefined;
83
+ validateArgs: (args?: ActorMethodParameters<A[M]> | undefined) => boolean;
81
84
  visit: VisitService<A>[M];
82
85
  reset: () => void;
83
86
  call: (eventOrReplaceArgs?: React.MouseEvent | ActorMethodParameters<A[M]>) => Promise<ActorMethodReturnType<A[M]> | undefined>;
@@ -90,6 +93,7 @@ export interface ActorHooksReturnType<A = BaseActor> {
90
93
  useActorState: () => UseActorState;
91
94
  useActorInterface: () => ServiceClass;
92
95
  useMethodNames: <Actor = A>() => FunctionName<Actor>[];
96
+ useMethodAttributes: <Actor = A>() => MethodAttributes<Actor>;
93
97
  useMethod: UseMethod<A>;
94
98
  useQueryCall: UseQueryCall<A>;
95
99
  useUpdateCall: UseUpdateCall<A>;
@@ -3,6 +3,7 @@ export * from "./useActorState";
3
3
  export * from "./useQueryCall";
4
4
  export * from "./useUpdateCall";
5
5
  export * from "./useMethodNames";
6
+ export * from "./useMethodAttributes";
6
7
  export * from "./useVisitMethod";
7
8
  export * from "./useVisitService";
8
9
  export * from "./useActorInterface";
@@ -19,6 +19,7 @@ __exportStar(require("./useActorState"), exports);
19
19
  __exportStar(require("./useQueryCall"), exports);
20
20
  __exportStar(require("./useUpdateCall"), exports);
21
21
  __exportStar(require("./useMethodNames"), exports);
22
+ __exportStar(require("./useMethodAttributes"), exports);
22
23
  __exportStar(require("./useVisitMethod"), exports);
23
24
  __exportStar(require("./useVisitService"), exports);
24
25
  __exportStar(require("./useActorInterface"), exports);
@@ -0,0 +1,7 @@
1
+ import { BaseActor } from "../../types";
2
+ /**
3
+ * Hook for accessing the method attributes of an actor.
4
+ *
5
+ * @returns An array of method attributes for the actor.
6
+ */
7
+ export declare const useMethodAttributes: <A = BaseActor>() => import("@ic-reactor/core/dist/classes/actor/types").MethodAttributes<A>;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useMethodAttributes = void 0;
4
+ const hooks_1 = require("./hooks");
5
+ /**
6
+ * Hook for accessing the method attributes of an actor.
7
+ *
8
+ * @returns An array of method attributes for the actor.
9
+ */
10
+ const useMethodAttributes = () => hooks_1.ActorHooks.useMethodAttributes();
11
+ exports.useMethodAttributes = useMethodAttributes;
@@ -4,10 +4,12 @@
4
4
  * It wraps child components, providing them access to actor-specific hooks and functionalities based on the provided canister ID and configuration.
5
5
  *
6
6
  * Props:
7
- * - `children`: React Node - The child components that will have access to the actor context.
8
7
  * - `canisterId` (optional): string - The Canister ID for actor interactions. If not provided, the default from `createActorContext` is used.
8
+ * - `idlFactory` (optional): IDL.InterfaceFactory - The IDL factory for the actor interface. If not provided, the default from `createActorContext` is used.
9
+ * - `didjsId` (optional): string - The DID.js ID for authentication. If not provided, the default from `createActorContext` is used.
9
10
  * - `loadingComponent` (optional): React Node - A component displayed during the loading/fetching state. Defaults to a simple message.
10
- * - `...restConfig`: Additional configuration options that will be merged with the default configuration provided during context creation.
11
+ * - `authenticatingComponent` (optional): React Node - A component displayed during the authentication state. Defaults to a simple message.
12
+ * - `children`: React Node - The child components that will have access to the actor context.
11
13
  *
12
14
  * Behavior:
13
15
  * - Validates the presence of a `canisterId`. Throws an error if it is missing, ensuring that a valid canister ID is always used for actor operations.
@@ -7,10 +7,12 @@ const hooks_1 = require("../hooks/actor/hooks");
7
7
  * It wraps child components, providing them access to actor-specific hooks and functionalities based on the provided canister ID and configuration.
8
8
  *
9
9
  * Props:
10
- * - `children`: React Node - The child components that will have access to the actor context.
11
10
  * - `canisterId` (optional): string - The Canister ID for actor interactions. If not provided, the default from `createActorContext` is used.
11
+ * - `idlFactory` (optional): IDL.InterfaceFactory - The IDL factory for the actor interface. If not provided, the default from `createActorContext` is used.
12
+ * - `didjsId` (optional): string - The DID.js ID for authentication. If not provided, the default from `createActorContext` is used.
12
13
  * - `loadingComponent` (optional): React Node - A component displayed during the loading/fetching state. Defaults to a simple message.
13
- * - `...restConfig`: Additional configuration options that will be merged with the default configuration provided during context creation.
14
+ * - `authenticatingComponent` (optional): React Node - A component displayed during the authentication state. Defaults to a simple message.
15
+ * - `children`: React Node - The child components that will have access to the actor context.
14
16
  *
15
17
  * Behavior:
16
18
  * - Validates the presence of a `canisterId`. Throws an error if it is missing, ensuring that a valid canister ID is always used for actor operations.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ic-reactor/react",
3
- "version": "1.4.4",
3
+ "version": "1.5.1",
4
4
  "description": "A React library for interacting with Internet Computer canisters",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  "node": ">=10"
36
36
  },
37
37
  "dependencies": {
38
- "@ic-reactor/core": "^1.4.2",
38
+ "@ic-reactor/core": "^1.5.0",
39
39
  "zustand-utils": "^1.3"
40
40
  },
41
41
  "peerDependencies": {
@@ -47,5 +47,5 @@
47
47
  "react": ">=16.8",
48
48
  "zustand": "4.5"
49
49
  },
50
- "gitHead": "89bab92f75cbbe39c9bdd6a0ac60344c6844ce5d"
50
+ "gitHead": "02efba3e5948cb004777b8b54d623c4c537d3354"
51
51
  }