@ic-reactor/core 2.0.1 → 3.0.0-beta.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.
Files changed (123) hide show
  1. package/dist/client.d.ts +161 -0
  2. package/dist/client.d.ts.map +1 -0
  3. package/dist/client.js +499 -0
  4. package/dist/client.js.map +1 -0
  5. package/dist/display/helper.d.ts +10 -0
  6. package/dist/display/helper.d.ts.map +1 -0
  7. package/dist/display/helper.js +67 -0
  8. package/dist/display/helper.js.map +1 -0
  9. package/dist/display/index.d.ts +4 -0
  10. package/dist/display/index.d.ts.map +1 -0
  11. package/dist/display/index.js +4 -0
  12. package/dist/display/index.js.map +1 -0
  13. package/dist/display/types.d.ts +31 -0
  14. package/dist/display/types.d.ts.map +1 -0
  15. package/dist/display/types.js +2 -0
  16. package/dist/display/types.js.map +1 -0
  17. package/dist/display/visitor.d.ts +28 -0
  18. package/dist/display/visitor.d.ts.map +1 -0
  19. package/dist/display/visitor.js +318 -0
  20. package/dist/display/visitor.js.map +1 -0
  21. package/dist/display-reactor.d.ts +245 -0
  22. package/dist/display-reactor.d.ts.map +1 -0
  23. package/dist/display-reactor.js +331 -0
  24. package/dist/display-reactor.js.map +1 -0
  25. package/dist/errors/index.d.ts +118 -0
  26. package/dist/errors/index.d.ts.map +1 -0
  27. package/dist/errors/index.js +204 -0
  28. package/dist/errors/index.js.map +1 -0
  29. package/dist/index.d.ts +9 -8
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +9 -47
  32. package/dist/index.js.map +1 -0
  33. package/dist/reactor.d.ts +133 -0
  34. package/dist/reactor.d.ts.map +1 -0
  35. package/dist/reactor.js +325 -0
  36. package/dist/reactor.js.map +1 -0
  37. package/dist/types/client.d.ts +89 -0
  38. package/dist/types/client.d.ts.map +1 -0
  39. package/dist/types/client.js +2 -0
  40. package/dist/types/client.js.map +1 -0
  41. package/dist/types/index.d.ts +6 -0
  42. package/dist/types/index.d.ts.map +1 -0
  43. package/dist/types/index.js +6 -0
  44. package/dist/types/index.js.map +1 -0
  45. package/dist/types/reactor.d.ts +117 -0
  46. package/dist/types/reactor.d.ts.map +1 -0
  47. package/dist/types/reactor.js +2 -0
  48. package/dist/types/reactor.js.map +1 -0
  49. package/dist/types/result.d.ts +48 -0
  50. package/dist/types/result.d.ts.map +1 -0
  51. package/dist/types/result.js +2 -0
  52. package/dist/types/result.js.map +1 -0
  53. package/dist/types/transform.d.ts +7 -0
  54. package/dist/types/transform.d.ts.map +1 -0
  55. package/dist/types/transform.js +2 -0
  56. package/dist/types/transform.js.map +1 -0
  57. package/dist/types/variant.d.ts +18 -0
  58. package/dist/types/variant.d.ts.map +1 -0
  59. package/dist/types/variant.js +2 -0
  60. package/dist/types/variant.js.map +1 -0
  61. package/dist/utils/agent.d.ts +30 -1
  62. package/dist/utils/agent.d.ts.map +1 -0
  63. package/dist/utils/agent.js +118 -16
  64. package/dist/utils/agent.js.map +1 -0
  65. package/dist/utils/candid.d.ts +39 -1
  66. package/dist/utils/candid.d.ts.map +1 -0
  67. package/dist/utils/candid.js +76 -16
  68. package/dist/utils/candid.js.map +1 -0
  69. package/dist/utils/constants.d.ts +3 -4
  70. package/dist/utils/constants.d.ts.map +1 -0
  71. package/dist/utils/constants.js +7 -11
  72. package/dist/utils/constants.js.map +1 -0
  73. package/dist/utils/helper.d.ts +16 -39
  74. package/dist/utils/helper.d.ts.map +1 -0
  75. package/dist/utils/helper.js +53 -155
  76. package/dist/utils/helper.js.map +1 -0
  77. package/dist/utils/index.d.ts +4 -5
  78. package/dist/utils/index.d.ts.map +1 -0
  79. package/dist/utils/index.js +5 -49
  80. package/dist/utils/index.js.map +1 -0
  81. package/dist/utils/polling.d.ts +176 -0
  82. package/dist/utils/polling.d.ts.map +1 -0
  83. package/dist/utils/polling.js +170 -0
  84. package/dist/utils/polling.js.map +1 -0
  85. package/dist/version.d.ts +5 -0
  86. package/dist/version.d.ts.map +1 -0
  87. package/dist/version.js +5 -0
  88. package/dist/version.js.map +1 -0
  89. package/package.json +65 -39
  90. package/LICENSE.md +0 -8
  91. package/README.md +0 -283
  92. package/dist/classes/actor/index.d.ts +0 -34
  93. package/dist/classes/actor/index.js +0 -245
  94. package/dist/classes/actor/types.d.ts +0 -113
  95. package/dist/classes/actor/types.js +0 -2
  96. package/dist/classes/adapter/index.d.ts +0 -19
  97. package/dist/classes/adapter/index.js +0 -140
  98. package/dist/classes/adapter/types.d.ts +0 -14
  99. package/dist/classes/adapter/types.js +0 -2
  100. package/dist/classes/agent/index.d.ts +0 -37
  101. package/dist/classes/agent/index.js +0 -221
  102. package/dist/classes/agent/types.d.ts +0 -87
  103. package/dist/classes/agent/types.js +0 -2
  104. package/dist/classes/index.d.ts +0 -3
  105. package/dist/classes/index.js +0 -19
  106. package/dist/classes/types.d.ts +0 -15
  107. package/dist/classes/types.js +0 -20
  108. package/dist/createActorManager.d.ts +0 -12
  109. package/dist/createActorManager.js +0 -17
  110. package/dist/createAgentManager.d.ts +0 -12
  111. package/dist/createAgentManager.js +0 -17
  112. package/dist/createCandidAdapter.d.ts +0 -11
  113. package/dist/createCandidAdapter.js +0 -16
  114. package/dist/createReactorCore.d.ts +0 -10
  115. package/dist/createReactorCore.js +0 -112
  116. package/dist/createReactorStore.d.ts +0 -11
  117. package/dist/createReactorStore.js +0 -31
  118. package/dist/types.d.ts +0 -96
  119. package/dist/types.js +0 -17
  120. package/dist/utils/hash.d.ts +0 -12
  121. package/dist/utils/hash.js +0 -70
  122. package/dist/utils/principal.d.ts +0 -1
  123. package/dist/utils/principal.js +0 -17
@@ -0,0 +1,245 @@
1
+ import { Reactor } from "./reactor";
2
+ import { ActorMethodParameters, ActorMethodReturnType, FunctionName, ReactorArgs, ReactorReturnOk, ActorMethodCodecs, ReactorParameters, BaseActor } from "./types/reactor";
3
+ import { ValidationIssue } from "./errors";
4
+ /**
5
+ * Validation result returned by a validator function.
6
+ * Either success (true) or failure with issues.
7
+ */
8
+ export type ValidationResult = {
9
+ success: true;
10
+ } | {
11
+ success: false;
12
+ issues: ValidationIssue[];
13
+ };
14
+ /**
15
+ * A validator function that validates method arguments.
16
+ * Receives display types (strings for Principal, bigint, etc.).
17
+ *
18
+ * @param args - The display-type arguments to validate
19
+ * @returns ValidationResult indicating success or failure with issues
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Validator receives display types
24
+ * reactor.registerValidator("transfer", ([input]) => {
25
+ * const issues = []
26
+ *
27
+ * // input.to is string (not Principal)
28
+ * if (!input.to) {
29
+ * issues.push({ path: ["to"], message: "Recipient is required" })
30
+ * }
31
+ *
32
+ * // input.amount is string (not bigint)
33
+ * if (!/^\d+$/.test(input.amount)) {
34
+ * issues.push({ path: ["amount"], message: "Must be a valid number" })
35
+ * }
36
+ *
37
+ * return issues.length > 0 ? { success: false, issues } : { success: true }
38
+ * })
39
+ * ```
40
+ */
41
+ export type Validator<Args = unknown[]> = (args: Args) => ValidationResult | Promise<ValidationResult>;
42
+ /**
43
+ * Validator that receives display types for a specific method.
44
+ */
45
+ export type DisplayValidator<A, M extends FunctionName<A>> = Validator<ReactorArgs<A, M, "display">>;
46
+ export type DisplayReactorParameters<A = BaseActor> = ReactorParameters<A> & {
47
+ /**
48
+ * Optional initial validators to register.
49
+ * Validators receive display types (strings for Principal, bigint, etc.)
50
+ */
51
+ validators?: Partial<{
52
+ [M in FunctionName<A>]: DisplayValidator<A, M>;
53
+ }>;
54
+ };
55
+ /**
56
+ * DisplayReactor provides automatic type transformations between Candid and
57
+ * display-friendly types, plus optional argument validation.
58
+ *
59
+ * ### Type Transformations
60
+ * - `bigint` → `string` (for JSON/UI display)
61
+ * - `Principal` → `string` (text representation)
62
+ * - `[T] | []` → `T | null` (optional unwrapping)
63
+ * - Small blobs → hex strings
64
+ *
65
+ * ### Validation (Optional)
66
+ * Register validators to check arguments before canister calls.
67
+ * Validators receive **display types** (strings), making them perfect for
68
+ * form validation.
69
+ *
70
+ * @typeParam A - The actor service type
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * import { DisplayReactor } from "@ic-reactor/core"
75
+ *
76
+ * const reactor = new DisplayReactor<_SERVICE>({
77
+ * clientManager,
78
+ * canisterId: "...",
79
+ * idlFactory,
80
+ * })
81
+ *
82
+ * // Optional: Add validation
83
+ * reactor.registerValidator("transfer", ([input]) => {
84
+ * if (!input.to) {
85
+ * return {
86
+ * success: false,
87
+ * issues: [{ path: ["to"], message: "Recipient is required" }]
88
+ * }
89
+ * }
90
+ * return { success: true }
91
+ * })
92
+ *
93
+ * // Call with display types
94
+ * await reactor.callMethod({
95
+ * functionName: "transfer",
96
+ * args: [{ to: "aaaaa-aa", amount: "100" }], // strings!
97
+ * })
98
+ * ```
99
+ */
100
+ export declare class DisplayReactor<A = BaseActor> extends Reactor<A, "display"> {
101
+ readonly transform = "display";
102
+ private codecs;
103
+ private validators;
104
+ constructor(config: DisplayReactorParameters<A>);
105
+ /**
106
+ * Initialize codecs from IDL factory for automatic type transformations
107
+ */
108
+ private initializeCodecs;
109
+ /**
110
+ * Get a codec for a specific method.
111
+ * Returns the args and result codecs for bidirectional transformation.
112
+ * @param methodName - The name of the method
113
+ * @returns Object with args and result codecs, or null if not found
114
+ */
115
+ getCodec<M extends FunctionName<A>>(methodName: M): ActorMethodCodecs<A, M> | null;
116
+ /**
117
+ * Register a validator for a specific method.
118
+ * Validators receive display types (strings for Principal/bigint).
119
+ *
120
+ * @param methodName - The name of the method to validate
121
+ * @param validator - The validator function receiving display types
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * // input.to is string, input.amount is string
126
+ * reactor.registerValidator("transfer", ([input]) => {
127
+ * if (!/^\d+$/.test(input.amount)) {
128
+ * return {
129
+ * success: false,
130
+ * issues: [{ path: ["amount"], message: "Must be a valid number" }]
131
+ * }
132
+ * }
133
+ * return { success: true }
134
+ * })
135
+ * ```
136
+ */
137
+ registerValidator<M extends FunctionName<A>>(methodName: M, validator: DisplayValidator<A, M>): void;
138
+ /**
139
+ * Unregister a validator for a specific method.
140
+ */
141
+ unregisterValidator<M extends FunctionName<A>>(methodName: M): void;
142
+ /**
143
+ * Check if a method has a registered validator.
144
+ */
145
+ hasValidator<M extends FunctionName<A>>(methodName: M): boolean;
146
+ /**
147
+ * Validate arguments without calling the canister.
148
+ * Arguments are in display format (strings for Principal/bigint).
149
+ * Useful for form validation before submission.
150
+ *
151
+ * @param methodName - The name of the method
152
+ * @param args - The display-type arguments to validate
153
+ * @returns ValidationResult indicating success or failure
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * // Validate form data before submission
158
+ * const result = await reactor.validate("transfer", [{
159
+ * to: formData.recipient, // string
160
+ * amount: formData.amount, // string
161
+ * }])
162
+ *
163
+ * if (!result.success) {
164
+ * result.issues.forEach(issue => {
165
+ * form.setError(issue.path[0], issue.message)
166
+ * })
167
+ * }
168
+ * ```
169
+ */
170
+ validate<M extends FunctionName<A>>(methodName: M, args: ReactorArgs<A, M, "display">): Promise<ValidationResult>;
171
+ /**
172
+ * Call a method with async validation support.
173
+ * Use this instead of callMethod() when you have async validators.
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * // Async validator (e.g., check if address is blocked)
178
+ * reactor.registerValidator("transfer", async ([input]) => {
179
+ * const isBlocked = await checkBlocklist(input.to)
180
+ * if (isBlocked) {
181
+ * return {
182
+ * success: false,
183
+ * issues: [{ path: ["to"], message: "Address is blocked" }]
184
+ * }
185
+ * }
186
+ * return { success: true }
187
+ * })
188
+ *
189
+ * await reactor.callMethodWithValidation({
190
+ * functionName: "transfer",
191
+ * args: [{ to: "...", amount: "100" }],
192
+ * })
193
+ * ```
194
+ */
195
+ callMethodWithValidation<M extends FunctionName<A>>(params: {
196
+ functionName: M;
197
+ args?: ReactorArgs<A, M, "display">;
198
+ callConfig?: Parameters<Reactor<A, "display">["callMethod"]>[0]["callConfig"];
199
+ }): Promise<ReactorReturnOk<A, M, "display">>;
200
+ /**
201
+ * Transform arguments before calling the actor method.
202
+ * 1. Validates display-type args (if validator registered)
203
+ * 2. Converts Display → Candid
204
+ */
205
+ protected transformArgs<M extends FunctionName<A>>(methodName: M, args?: ReactorArgs<A, M, "display">): ActorMethodParameters<A[M]>;
206
+ /**
207
+ * Transform the result after calling the actor method.
208
+ * Always extracts the Ok value from Result types (throws CanisterError on Err).
209
+ * Also converts Candid → Display format.
210
+ */
211
+ protected transformResult<M extends FunctionName<A>>(methodName: M, result: ActorMethodReturnType<A[M]>): ReactorReturnOk<A, M, "display">;
212
+ }
213
+ /**
214
+ * Create a validator from a Zod schema.
215
+ * This is a utility function to easily integrate Zod schemas as validators.
216
+ *
217
+ * @param schema - A Zod schema to validate against
218
+ * @returns A Validator function compatible with DisplayReactor
219
+ *
220
+ * @example
221
+ * ```typescript
222
+ * import { z } from "zod"
223
+ * import { fromZodSchema } from "@ic-reactor/core"
224
+ *
225
+ * const transferSchema = z.object({
226
+ * to: z.string().min(1, "Recipient is required"),
227
+ * amount: z.string().regex(/^\d+$/, "Must be a valid number"),
228
+ * })
229
+ *
230
+ * reactor.registerValidator("transfer", fromZodSchema(transferSchema))
231
+ * ```
232
+ */
233
+ export declare function fromZodSchema<T>(schema: {
234
+ safeParse: (data: unknown) => {
235
+ success: boolean;
236
+ error?: {
237
+ issues: Array<{
238
+ path: (string | number)[];
239
+ message: string;
240
+ code?: string;
241
+ }>;
242
+ };
243
+ };
244
+ }): Validator<T[]>;
245
+ //# sourceMappingURL=display-reactor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-reactor.d.ts","sourceRoot":"","sources":["../src/display-reactor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,331 @@
1
+ import { Reactor } from "./reactor";
2
+ import { didToDisplayCodec, transformArgsWithCodec, transformResultWithCodec, didTypeFromArray, } from "./display";
3
+ import { extractOkResult } from "./utils/helper";
4
+ import { ValidationError } from "./errors";
5
+ // ============================================================================
6
+ // DisplayReactor
7
+ // ============================================================================
8
+ /**
9
+ * DisplayReactor provides automatic type transformations between Candid and
10
+ * display-friendly types, plus optional argument validation.
11
+ *
12
+ * ### Type Transformations
13
+ * - `bigint` → `string` (for JSON/UI display)
14
+ * - `Principal` → `string` (text representation)
15
+ * - `[T] | []` → `T | null` (optional unwrapping)
16
+ * - Small blobs → hex strings
17
+ *
18
+ * ### Validation (Optional)
19
+ * Register validators to check arguments before canister calls.
20
+ * Validators receive **display types** (strings), making them perfect for
21
+ * form validation.
22
+ *
23
+ * @typeParam A - The actor service type
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { DisplayReactor } from "@ic-reactor/core"
28
+ *
29
+ * const reactor = new DisplayReactor<_SERVICE>({
30
+ * clientManager,
31
+ * canisterId: "...",
32
+ * idlFactory,
33
+ * })
34
+ *
35
+ * // Optional: Add validation
36
+ * reactor.registerValidator("transfer", ([input]) => {
37
+ * if (!input.to) {
38
+ * return {
39
+ * success: false,
40
+ * issues: [{ path: ["to"], message: "Recipient is required" }]
41
+ * }
42
+ * }
43
+ * return { success: true }
44
+ * })
45
+ *
46
+ * // Call with display types
47
+ * await reactor.callMethod({
48
+ * functionName: "transfer",
49
+ * args: [{ to: "aaaaa-aa", amount: "100" }], // strings!
50
+ * })
51
+ * ```
52
+ */
53
+ export class DisplayReactor extends Reactor {
54
+ constructor(config) {
55
+ super(config);
56
+ Object.defineProperty(this, "transform", {
57
+ enumerable: true,
58
+ configurable: true,
59
+ writable: true,
60
+ value: "display"
61
+ });
62
+ Object.defineProperty(this, "codecs", {
63
+ enumerable: true,
64
+ configurable: true,
65
+ writable: true,
66
+ value: new Map()
67
+ });
68
+ Object.defineProperty(this, "validators", {
69
+ enumerable: true,
70
+ configurable: true,
71
+ writable: true,
72
+ value: new Map()
73
+ });
74
+ this.initializeCodecs();
75
+ // Register initial validators if provided
76
+ if (config.validators) {
77
+ for (const [methodName, validator] of Object.entries(config.validators)) {
78
+ if (validator) {
79
+ this.validators.set(methodName, validator);
80
+ }
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Initialize codecs from IDL factory for automatic type transformations
86
+ */
87
+ initializeCodecs() {
88
+ try {
89
+ const fields = this.getServiceInterface()?._fields;
90
+ if (!fields) {
91
+ throw new Error("No fields found");
92
+ }
93
+ for (const [methodName, funcType] of fields) {
94
+ // Generate args codec
95
+ const argsIdlType = didTypeFromArray(funcType.argTypes);
96
+ // Generate result codec
97
+ const retIdlType = didTypeFromArray(funcType.retTypes);
98
+ // Set codec in map
99
+ this.codecs.set(methodName, {
100
+ args: didToDisplayCodec(argsIdlType),
101
+ result: didToDisplayCodec(retIdlType),
102
+ });
103
+ }
104
+ }
105
+ catch (error) {
106
+ console.error("Failed to initialize codecs:", error);
107
+ }
108
+ }
109
+ // ============================================================================
110
+ // Codec Methods
111
+ // ============================================================================
112
+ /**
113
+ * Get a codec for a specific method.
114
+ * Returns the args and result codecs for bidirectional transformation.
115
+ * @param methodName - The name of the method
116
+ * @returns Object with args and result codecs, or null if not found
117
+ */
118
+ getCodec(methodName) {
119
+ const cached = this.codecs.get(methodName);
120
+ if (cached) {
121
+ return cached;
122
+ }
123
+ return null;
124
+ }
125
+ // ============================================================================
126
+ // Validation Methods
127
+ // ============================================================================
128
+ /**
129
+ * Register a validator for a specific method.
130
+ * Validators receive display types (strings for Principal/bigint).
131
+ *
132
+ * @param methodName - The name of the method to validate
133
+ * @param validator - The validator function receiving display types
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * // input.to is string, input.amount is string
138
+ * reactor.registerValidator("transfer", ([input]) => {
139
+ * if (!/^\d+$/.test(input.amount)) {
140
+ * return {
141
+ * success: false,
142
+ * issues: [{ path: ["amount"], message: "Must be a valid number" }]
143
+ * }
144
+ * }
145
+ * return { success: true }
146
+ * })
147
+ * ```
148
+ */
149
+ registerValidator(methodName, validator) {
150
+ this.validators.set(methodName, validator);
151
+ }
152
+ /**
153
+ * Unregister a validator for a specific method.
154
+ */
155
+ unregisterValidator(methodName) {
156
+ this.validators.delete(methodName);
157
+ }
158
+ /**
159
+ * Check if a method has a registered validator.
160
+ */
161
+ hasValidator(methodName) {
162
+ return this.validators.has(methodName);
163
+ }
164
+ /**
165
+ * Validate arguments without calling the canister.
166
+ * Arguments are in display format (strings for Principal/bigint).
167
+ * Useful for form validation before submission.
168
+ *
169
+ * @param methodName - The name of the method
170
+ * @param args - The display-type arguments to validate
171
+ * @returns ValidationResult indicating success or failure
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * // Validate form data before submission
176
+ * const result = await reactor.validate("transfer", [{
177
+ * to: formData.recipient, // string
178
+ * amount: formData.amount, // string
179
+ * }])
180
+ *
181
+ * if (!result.success) {
182
+ * result.issues.forEach(issue => {
183
+ * form.setError(issue.path[0], issue.message)
184
+ * })
185
+ * }
186
+ * ```
187
+ */
188
+ async validate(methodName, args) {
189
+ const validator = this.validators.get(methodName);
190
+ if (!validator) {
191
+ return { success: true };
192
+ }
193
+ return validator(args);
194
+ }
195
+ /**
196
+ * Call a method with async validation support.
197
+ * Use this instead of callMethod() when you have async validators.
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * // Async validator (e.g., check if address is blocked)
202
+ * reactor.registerValidator("transfer", async ([input]) => {
203
+ * const isBlocked = await checkBlocklist(input.to)
204
+ * if (isBlocked) {
205
+ * return {
206
+ * success: false,
207
+ * issues: [{ path: ["to"], message: "Address is blocked" }]
208
+ * }
209
+ * }
210
+ * return { success: true }
211
+ * })
212
+ *
213
+ * await reactor.callMethodWithValidation({
214
+ * functionName: "transfer",
215
+ * args: [{ to: "...", amount: "100" }],
216
+ * })
217
+ * ```
218
+ */
219
+ async callMethodWithValidation(params) {
220
+ // Run async validation first (on display types)
221
+ if (params.args) {
222
+ const result = await this.validate(params.functionName, params.args);
223
+ if (!result.success) {
224
+ throw new ValidationError(String(params.functionName), result.issues);
225
+ }
226
+ }
227
+ // Skip synchronous validation in transformArgs by temporarily removing validator
228
+ const validator = this.validators.get(params.functionName);
229
+ if (validator) {
230
+ this.validators.delete(params.functionName);
231
+ }
232
+ try {
233
+ return await this.callMethod(params);
234
+ }
235
+ finally {
236
+ // Restore validator
237
+ if (validator) {
238
+ this.validators.set(params.functionName, validator);
239
+ }
240
+ }
241
+ }
242
+ // ============================================================================
243
+ // Transform Methods
244
+ // ============================================================================
245
+ /**
246
+ * Transform arguments before calling the actor method.
247
+ * 1. Validates display-type args (if validator registered)
248
+ * 2. Converts Display → Candid
249
+ */
250
+ transformArgs(methodName, args) {
251
+ // 1. Validate FIRST (on display types)
252
+ const validator = this.validators.get(methodName);
253
+ if (validator && args) {
254
+ const result = validator(args);
255
+ // Handle Promise (async validator)
256
+ if (result &&
257
+ typeof result.then === "function") {
258
+ throw new Error(`Async validators are not supported in callMethod(). ` +
259
+ `Use reactor.callMethodWithValidation() for async validation.`);
260
+ }
261
+ const syncResult = result;
262
+ if (!syncResult.success) {
263
+ throw new ValidationError(String(methodName), syncResult.issues);
264
+ }
265
+ }
266
+ // 2. THEN transform: Display → Candid
267
+ if (this.codecs.has(methodName)) {
268
+ const codec = this.codecs.get(methodName);
269
+ return transformArgsWithCodec(codec.args, args);
270
+ }
271
+ if (!args) {
272
+ return [];
273
+ }
274
+ return args;
275
+ }
276
+ /**
277
+ * Transform the result after calling the actor method.
278
+ * Always extracts the Ok value from Result types (throws CanisterError on Err).
279
+ * Also converts Candid → Display format.
280
+ */
281
+ transformResult(methodName, result) {
282
+ let transformedResult = result;
283
+ // 1. Apply display transformation to the FULL result
284
+ if (this.codecs.has(methodName)) {
285
+ const codec = this.codecs.get(methodName);
286
+ transformedResult = transformResultWithCodec(codec.result, result);
287
+ }
288
+ // 2. Extract Ok value from the TRANSFORMED (or raw) result
289
+ // This handles { ok: T } / { err: E } from Motoko/Rust canisters
290
+ return extractOkResult(transformedResult);
291
+ }
292
+ }
293
+ // ============================================================================
294
+ // Zod Integration Helper
295
+ // ============================================================================
296
+ /**
297
+ * Create a validator from a Zod schema.
298
+ * This is a utility function to easily integrate Zod schemas as validators.
299
+ *
300
+ * @param schema - A Zod schema to validate against
301
+ * @returns A Validator function compatible with DisplayReactor
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * import { z } from "zod"
306
+ * import { fromZodSchema } from "@ic-reactor/core"
307
+ *
308
+ * const transferSchema = z.object({
309
+ * to: z.string().min(1, "Recipient is required"),
310
+ * amount: z.string().regex(/^\d+$/, "Must be a valid number"),
311
+ * })
312
+ *
313
+ * reactor.registerValidator("transfer", fromZodSchema(transferSchema))
314
+ * ```
315
+ */
316
+ export function fromZodSchema(schema) {
317
+ return (args) => {
318
+ // Validate the first argument (common IC pattern)
319
+ const result = schema.safeParse(args[0]);
320
+ if (result.success) {
321
+ return { success: true };
322
+ }
323
+ const issues = result.error.issues.map((issue) => ({
324
+ path: issue.path,
325
+ message: issue.message,
326
+ code: issue.code,
327
+ }));
328
+ return { success: false, issues };
329
+ };
330
+ }
331
+ //# sourceMappingURL=display-reactor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-reactor.js","sourceRoot":"","sources":["../src/display-reactor.ts"],"names":[],"mappings":"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"}