@ic-reactor/core 3.0.1-beta.0 → 3.0.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 (74) hide show
  1. package/README.md +6 -4
  2. package/dist/client.d.ts +3 -1
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +48 -4
  5. package/dist/client.js.map +1 -1
  6. package/dist/display/types.d.ts +2 -2
  7. package/dist/display/types.d.ts.map +1 -1
  8. package/dist/display/visitor.d.ts +2 -1
  9. package/dist/display/visitor.d.ts.map +1 -1
  10. package/dist/display/visitor.js +146 -121
  11. package/dist/display/visitor.js.map +1 -1
  12. package/dist/display-reactor.d.ts +9 -92
  13. package/dist/display-reactor.d.ts.map +1 -1
  14. package/dist/display-reactor.js +5 -41
  15. package/dist/display-reactor.js.map +1 -1
  16. package/dist/reactor.d.ts +36 -4
  17. package/dist/reactor.d.ts.map +1 -1
  18. package/dist/reactor.js +101 -61
  19. package/dist/reactor.js.map +1 -1
  20. package/dist/types/client.d.ts +11 -0
  21. package/dist/types/client.d.ts.map +1 -1
  22. package/dist/types/display-reactor.d.ts +54 -0
  23. package/dist/types/display-reactor.d.ts.map +1 -0
  24. package/dist/types/display-reactor.js +5 -0
  25. package/dist/types/display-reactor.js.map +1 -0
  26. package/dist/types/index.d.ts +1 -0
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/dist/types/index.js +1 -0
  29. package/dist/types/index.js.map +1 -1
  30. package/dist/types/reactor.d.ts +10 -15
  31. package/dist/types/reactor.d.ts.map +1 -1
  32. package/dist/types/transform.d.ts +1 -1
  33. package/dist/types/transform.d.ts.map +1 -1
  34. package/dist/utils/constants.d.ts +1 -1
  35. package/dist/utils/constants.d.ts.map +1 -1
  36. package/dist/utils/constants.js +1 -1
  37. package/dist/utils/constants.js.map +1 -1
  38. package/dist/utils/helper.d.ts +20 -1
  39. package/dist/utils/helper.d.ts.map +1 -1
  40. package/dist/utils/helper.js +37 -6
  41. package/dist/utils/helper.js.map +1 -1
  42. package/dist/utils/index.d.ts +1 -0
  43. package/dist/utils/index.d.ts.map +1 -1
  44. package/dist/utils/index.js +1 -0
  45. package/dist/utils/index.js.map +1 -1
  46. package/dist/utils/zod.d.ts +34 -0
  47. package/dist/utils/zod.d.ts.map +1 -0
  48. package/dist/utils/zod.js +39 -0
  49. package/dist/utils/zod.js.map +1 -0
  50. package/package.json +7 -6
  51. package/src/client.ts +571 -0
  52. package/src/display/helper.ts +92 -0
  53. package/src/display/index.ts +3 -0
  54. package/src/display/types.ts +91 -0
  55. package/src/display/visitor.ts +415 -0
  56. package/src/display-reactor.ts +361 -0
  57. package/src/errors/index.ts +246 -0
  58. package/src/index.ts +8 -0
  59. package/src/reactor.ts +461 -0
  60. package/src/types/client.ts +110 -0
  61. package/src/types/display-reactor.ts +73 -0
  62. package/src/types/index.ts +6 -0
  63. package/src/types/reactor.ts +188 -0
  64. package/src/types/result.ts +50 -0
  65. package/src/types/transform.ts +29 -0
  66. package/src/types/variant.ts +39 -0
  67. package/src/utils/agent.ts +201 -0
  68. package/src/utils/candid.ts +112 -0
  69. package/src/utils/constants.ts +12 -0
  70. package/src/utils/helper.ts +155 -0
  71. package/src/utils/index.ts +5 -0
  72. package/src/utils/polling.ts +330 -0
  73. package/src/utils/zod.ts +56 -0
  74. package/src/version.ts +4 -0
@@ -0,0 +1,91 @@
1
+ import * as z from "zod"
2
+ import type { Principal } from "@icp-sdk/core/principal"
3
+ import type {
4
+ IsOptionalType,
5
+ IsBlobType,
6
+ UnionToTuple,
7
+ } from "../types/transform"
8
+ import type {
9
+ CandidVariantKey,
10
+ CandidVariantValue,
11
+ IsCandidVariant,
12
+ } from "../types/variant"
13
+
14
+ type VariantsOf<T> =
15
+ T extends Record<infer K extends CandidVariantKey<T>, any>
16
+ ? { _type: K } & (CandidVariantValue<T, K> extends null
17
+ ? {}
18
+ : { [P in K]: DisplayOf<CandidVariantValue<T, K>> })
19
+ : never
20
+
21
+ type VariantUnionOf<T> =
22
+ UnionToTuple<T> extends infer U
23
+ ? U extends any[]
24
+ ? { [K in keyof U]: VariantsOf<U[K]> }[number]
25
+ : never
26
+ : never
27
+
28
+ type CombineObjects<Required, Optional> = keyof Optional extends never
29
+ ? Required
30
+ : keyof Required extends never
31
+ ? Optional
32
+ : Required & Optional
33
+
34
+ type AsObject<T> = CombineObjects<
35
+ {
36
+ [K in keyof T as IsOptionalType<T[K]> extends true ? never : K]: DisplayOf<
37
+ T[K]
38
+ >
39
+ },
40
+ {
41
+ [K in keyof T as IsOptionalType<T[K]> extends true ? K : never]?: DisplayOf<
42
+ T[K]
43
+ >
44
+ }
45
+ >
46
+
47
+ type AsOptional<T> = T extends [infer U] ? NullishType<DisplayOf<U>> : never
48
+
49
+ export type BlobType = Uint8Array | number[] | string
50
+
51
+ export type NullishType<T> = T | null | undefined
52
+
53
+ export type DisplayCommonType<T> = T extends string
54
+ ? string
55
+ : T extends bigint
56
+ ? string
57
+ : T extends number
58
+ ? number
59
+ : T extends boolean
60
+ ? boolean
61
+ : T
62
+
63
+ export type DisplayOf<T> =
64
+ IsOptionalType<T> extends true
65
+ ? AsOptional<T>
66
+ : IsBlobType<T> extends true
67
+ ? BlobType
68
+ : IsCandidVariant<T> extends true
69
+ ? VariantUnionOf<T>
70
+ : T extends Array<[string, infer B]>
71
+ ? Record<string, DisplayOf<B>>
72
+ : T extends (infer U)[]
73
+ ? DisplayOf<U>[]
74
+ : T extends null
75
+ ? null
76
+ : T extends Principal
77
+ ? string
78
+ : T extends object
79
+ ? AsObject<T>
80
+ : DisplayCommonType<T>
81
+
82
+ export type DisplayCodec<TC = unknown, TD = DisplayOf<TC>> = z.ZodCodec<
83
+ z.ZodType<TC>,
84
+ z.ZodType<TD>
85
+ >
86
+
87
+ export interface ActorDisplayCodec<TC = unknown, TD = DisplayOf<TC>> {
88
+ codec: DisplayCodec<TC, TD>
89
+ asDisplay: (val: TC) => TD
90
+ asCandid: (val: TD) => TC
91
+ }
@@ -0,0 +1,415 @@
1
+ import * as z from "zod"
2
+ import { IDL } from "@icp-sdk/core/candid"
3
+ import { Principal } from "@icp-sdk/core/principal"
4
+ import {
5
+ createVariant,
6
+ nonNullish,
7
+ uint8ArrayToHex,
8
+ hexToUint8Array,
9
+ isNullish,
10
+ } from "../utils"
11
+
12
+ export class DisplayCodecVisitor extends IDL.Visitor<unknown, z.ZodTypeAny> {
13
+ private _recCache = new Map<IDL.RecClass, z.ZodTypeAny>()
14
+
15
+ visitType<T>(t: IDL.Type<T>, data: unknown): z.ZodTypeAny {
16
+ return t.accept(this, data)
17
+ }
18
+
19
+ visitPrimitive<T>(t: IDL.PrimitiveType<T>, data: unknown): z.ZodTypeAny {
20
+ return t.accept(this, data)
21
+ }
22
+
23
+ visitEmpty(_t: IDL.EmptyClass, _data: unknown): z.ZodTypeAny {
24
+ return z.never()
25
+ }
26
+
27
+ visitBool(_t: IDL.BoolClass, _data: unknown): z.ZodTypeAny {
28
+ return z.boolean()
29
+ }
30
+
31
+ visitNull(_t: IDL.NullClass, _data: unknown): z.ZodTypeAny {
32
+ return z.null()
33
+ }
34
+
35
+ visitReserved(_t: IDL.ReservedClass, _data: unknown): z.ZodTypeAny {
36
+ return z.any()
37
+ }
38
+
39
+ visitText(_t: IDL.TextClass, _data: unknown): z.ZodTypeAny {
40
+ return z.string()
41
+ }
42
+
43
+ visitNumber<T>(t: IDL.PrimitiveType<T>, data: unknown): z.ZodTypeAny {
44
+ return t.accept(this, data)
45
+ }
46
+
47
+ visitInt(_t: IDL.IntClass, _data: unknown): z.ZodTypeAny {
48
+ return z.codec(
49
+ z.bigint(), // Candid format
50
+ z.string(), // Display format
51
+ {
52
+ decode: (val) => (typeof val === "bigint" ? val.toString() : val),
53
+ encode: (val) => (typeof val === "string" ? BigInt(val) : val),
54
+ }
55
+ )
56
+ }
57
+
58
+ visitNat(_t: IDL.NatClass, _data: unknown): z.ZodTypeAny {
59
+ return z.codec(
60
+ z.bigint(), // Candid format
61
+ z.string(), // Display format
62
+ {
63
+ decode: (val) => (typeof val === "bigint" ? val.toString() : val),
64
+ encode: (val) => (typeof val === "string" ? BigInt(val) : val),
65
+ }
66
+ )
67
+ }
68
+
69
+ visitFloat(_t: IDL.FloatClass, _data: unknown): z.ZodTypeAny {
70
+ return z.number()
71
+ }
72
+
73
+ visitFixedInt(t: IDL.FixedIntClass, _data: unknown): z.ZodTypeAny {
74
+ const bits = t._bits
75
+
76
+ if (bits <= 32) {
77
+ // 32-bit integers stay as numbers
78
+ return z.number()
79
+ } else {
80
+ // 64-bit integers: bigint ↔ string
81
+ return z.codec(
82
+ z.bigint(), // Candid format
83
+ z.string(), // Display format
84
+ {
85
+ decode: (val) => (typeof val === "bigint" ? val.toString() : val),
86
+ encode: (val) => (typeof val === "string" ? BigInt(val) : val),
87
+ }
88
+ )
89
+ }
90
+ }
91
+
92
+ visitFixedNat(t: IDL.FixedNatClass, _data: unknown): z.ZodTypeAny {
93
+ const bits = t._bits
94
+
95
+ if (bits <= 32) {
96
+ return z.number()
97
+ } else {
98
+ return z.codec(
99
+ z.bigint(), // Candid format
100
+ z.string(), // Display format
101
+ {
102
+ decode: (val) => (typeof val === "bigint" ? val.toString() : val),
103
+ encode: (val) => (typeof val === "string" ? BigInt(val) : val),
104
+ }
105
+ )
106
+ }
107
+ }
108
+
109
+ visitPrincipal(_t: IDL.PrincipalClass, _data: unknown): z.ZodTypeAny {
110
+ const stringOrPrincipalSchema = z.union([z.string(), z.any()])
111
+
112
+ return z.codec(stringOrPrincipalSchema, stringOrPrincipalSchema, {
113
+ decode: (val) => {
114
+ if (val instanceof Principal) return val.toText()
115
+ if (typeof val === "string") return val
116
+ return String(val)
117
+ },
118
+ encode: (val) => {
119
+ if (typeof val === "string") return Principal.fromText(val)
120
+ if (val instanceof Principal) return val
121
+ return Principal.fromText(String(val))
122
+ },
123
+ })
124
+ }
125
+
126
+ visitConstruct<T>(t: IDL.ConstructType<T>, data: unknown): z.ZodTypeAny {
127
+ return t.accept(this, data)
128
+ }
129
+
130
+ visitVec<T>(
131
+ _t: IDL.VecClass<T>,
132
+ elemType: IDL.Type<T>,
133
+ _data: unknown
134
+ ): z.ZodTypeAny {
135
+ // Special case: Vec<Nat8> is a Blob (Uint8Array ↔ hex string)
136
+ if (elemType.name === "nat8") {
137
+ return z.codec(
138
+ z.union([z.instanceof(Uint8Array), z.array(z.number())]),
139
+ z.union([z.string(), z.instanceof(Uint8Array)]),
140
+ {
141
+ decode: (val) => {
142
+ if (!val) return val
143
+ if (val.length <= 512) return uint8ArrayToHex(val)
144
+ return val as Uint8Array<ArrayBuffer>
145
+ },
146
+ encode: (val) => {
147
+ if (typeof val === "string") {
148
+ return hexToUint8Array(val)
149
+ }
150
+ return val
151
+ },
152
+ }
153
+ )
154
+ }
155
+ // Regular array: codec each element
156
+ const elemCodec = elemType.accept(this, null)
157
+
158
+ // Special case: Vec<Tuple(Text, Value)> → Map (for key-value pairs)
159
+ const isTextTuple =
160
+ elemType instanceof IDL.TupleClass && elemType._fields.length === 2
161
+
162
+ if (isTextTuple) {
163
+ return z.codec(z.any(), z.any(), {
164
+ decode: (val) => {
165
+ if (!Array.isArray(val)) return val
166
+ return Object.fromEntries(
167
+ val.map((elem) => elemCodec.decode(elem)) as [string, any][]
168
+ )
169
+ },
170
+ encode: (val) => {
171
+ // If already array, encode elements directly
172
+ if (Array.isArray(val)) {
173
+ return val.map((elem) => elemCodec.encode(elem))
174
+ }
175
+ const entries =
176
+ val && typeof val === "object" ? Object.entries(val) : val
177
+ if (!Array.isArray(entries)) return entries
178
+ return entries.map((elem) => elemCodec.encode(elem))
179
+ },
180
+ })
181
+ }
182
+
183
+ return z.codec(z.any(), z.any(), {
184
+ decode: (val) => {
185
+ if (!Array.isArray(val)) return val
186
+ return val.map((elem) => elemCodec.decode(elem))
187
+ },
188
+ encode: (val) => {
189
+ if (!Array.isArray(val)) return val
190
+ return val.map((elem) => elemCodec.encode(elem))
191
+ },
192
+ })
193
+ }
194
+
195
+ visitOpt<T>(
196
+ _t: IDL.OptClass<T>,
197
+ elemType: IDL.Type<T>,
198
+ _data: unknown
199
+ ): z.ZodTypeAny {
200
+ const elemCodec = elemType.accept(this, null)
201
+
202
+ return z.codec(z.any(), z.any(), {
203
+ decode: (val) => {
204
+ if (!Array.isArray(val) || val.length === 0) return undefined
205
+ return elemCodec.decode(val[0])
206
+ },
207
+ encode: (val) => {
208
+ if (isNullish(val)) return [] as []
209
+ return [elemCodec.encode(val)] as [any]
210
+ },
211
+ })
212
+ }
213
+
214
+ visitRecord(
215
+ _t: IDL.RecordClass,
216
+ fields: Array<[string, IDL.Type]>,
217
+ _data: unknown
218
+ ): z.ZodTypeAny {
219
+ const fieldEntries = fields.map(([fieldName, fieldType]) => ({
220
+ fieldName,
221
+ codec: fieldType.accept(this, null),
222
+ }))
223
+
224
+ return z.codec(z.any(), z.any(), {
225
+ decode: (val) => {
226
+ if (!val || typeof val !== "object") return val
227
+ return Object.fromEntries(
228
+ fieldEntries.map(({ fieldName, codec }) => [
229
+ fieldName,
230
+ codec.decode(val[fieldName]),
231
+ ])
232
+ )
233
+ },
234
+ encode: (val) => {
235
+ if (!val || typeof val !== "object") return val
236
+ return Object.fromEntries(
237
+ fieldEntries.map(({ fieldName, codec }) => [
238
+ fieldName,
239
+ codec.encode(val[fieldName]),
240
+ ])
241
+ )
242
+ },
243
+ })
244
+ }
245
+
246
+ visitTuple<T extends any[]>(
247
+ _t: IDL.TupleClass<T>,
248
+ components: IDL.Type[],
249
+ _data: unknown
250
+ ): z.ZodTypeAny {
251
+ const componentCodecs: any = components.map((component) =>
252
+ component.accept(this, null)
253
+ )
254
+
255
+ return z.codec(z.any(), z.any(), {
256
+ decode: (val) => {
257
+ if (!Array.isArray(val)) return val
258
+ return val.map((elem: any, idx: number) =>
259
+ componentCodecs[idx].decode(elem)
260
+ )
261
+ },
262
+ encode: (val) => {
263
+ if (!Array.isArray(val)) return val
264
+ return val.map((elem: any, idx: number) =>
265
+ componentCodecs[idx].encode(elem)
266
+ )
267
+ },
268
+ })
269
+ }
270
+
271
+ visitVariant(
272
+ _t: IDL.VariantClass,
273
+ fields: Array<[string, IDL.Type]>,
274
+ _data: unknown
275
+ ): z.ZodTypeAny {
276
+ const variantCodecs: Record<string, any> = {}
277
+ for (const [variantName, variantType] of fields) {
278
+ variantCodecs[variantName] = variantType.accept(this, null)
279
+ }
280
+
281
+ const decode = (codec: any, val: any) =>
282
+ codec.decode ? codec.decode(val) : val
283
+ const encode = (codec: any, val: any) =>
284
+ codec.encode ? codec.encode(val) : val
285
+
286
+ return z.codec(z.any(), z.any(), {
287
+ decode: (val: any) => {
288
+ if (
289
+ !val ||
290
+ typeof val !== "object" ||
291
+ Array.isArray(val) ||
292
+ val instanceof Principal ||
293
+ "_type" in val
294
+ ) {
295
+ return val
296
+ }
297
+
298
+ const keys = Object.keys(val)
299
+ if (keys.length !== 1) return val
300
+
301
+ try {
302
+ const extracted = createVariant(val)
303
+ const key = extracted._type
304
+ const fieldType = fields.find(([n]) => n === key)?.[1]
305
+ if (fieldType?.name === "null") return { _type: key }
306
+
307
+ if (key in variantCodecs && nonNullish(extracted[key])) {
308
+ return {
309
+ _type: key,
310
+ [key]: decode(variantCodecs[key], extracted[key]),
311
+ }
312
+ }
313
+ return extracted
314
+ } catch {
315
+ return val
316
+ }
317
+ },
318
+ encode: (val: any) => {
319
+ if (
320
+ !val ||
321
+ typeof val !== "object" ||
322
+ Array.isArray(val) ||
323
+ val instanceof Principal
324
+ ) {
325
+ return val
326
+ }
327
+
328
+ try {
329
+ // Format 1: With _type property (from decode output)
330
+ if ("_type" in val) {
331
+ const key = val._type
332
+ const fieldType = fields.find(([n]) => n === key)?.[1]
333
+ if (fieldType?.name === "null") return { [key]: null }
334
+
335
+ if (key in variantCodecs && nonNullish(val[key])) {
336
+ return { [key]: encode(variantCodecs[key], val[key]) }
337
+ }
338
+ return { [key]: null }
339
+ }
340
+
341
+ // Format 2: Without _type (direct variant format from forms: { Add: value })
342
+ const keys = Object.keys(val)
343
+ if (keys.length === 1) {
344
+ const key = keys[0]
345
+ const fieldType = fields.find(([n]) => n === key)?.[1]
346
+ if (fieldType?.name === "null") return { [key]: null }
347
+
348
+ if (key in variantCodecs && nonNullish(val[key])) {
349
+ return { [key]: encode(variantCodecs[key], val[key]) }
350
+ }
351
+ return { [key]: null }
352
+ }
353
+
354
+ // Unknown format - return as-is
355
+ return val
356
+ } catch {
357
+ return val
358
+ }
359
+ },
360
+ })
361
+ }
362
+
363
+ visitRec<T>(
364
+ t: IDL.RecClass<T>,
365
+ ty: IDL.ConstructType<T>,
366
+ data: unknown
367
+ ): z.ZodTypeAny {
368
+ if (this._recCache.has(t)) return this._recCache.get(t)!
369
+
370
+ const lazyCodec = z.codec(z.any(), z.any(), {
371
+ decode: (val: any) => {
372
+ const codec = ty.accept(this, data)
373
+ return codec.decode ? codec.decode(val) : val
374
+ },
375
+ encode: (val: any) => {
376
+ const codec = ty.accept(this, data)
377
+ return codec.encode ? codec.encode(val) : val
378
+ },
379
+ })
380
+
381
+ this._recCache.set(t, lazyCodec)
382
+ return lazyCodec
383
+ }
384
+
385
+ visitFunc(_t: IDL.FuncClass, _data: unknown): z.ZodTypeAny {
386
+ return z.codec(z.any(), z.any(), {
387
+ decode: (val: any) => {
388
+ if (!Array.isArray(val) || val.length !== 2) return val
389
+ const [principal, method] = val
390
+ return [
391
+ principal instanceof Principal ? principal.toText() : principal,
392
+ method,
393
+ ]
394
+ },
395
+ encode: (val: any) => {
396
+ if (!Array.isArray(val) || val.length !== 2) return val
397
+ const [principalStr, method] = val
398
+ return [
399
+ typeof principalStr === "string"
400
+ ? Principal.fromText(principalStr)
401
+ : principalStr,
402
+ method,
403
+ ]
404
+ },
405
+ })
406
+ }
407
+
408
+ visitService(_t: IDL.ServiceClass, _data: unknown): z.ZodTypeAny {
409
+ return z.codec(z.any(), z.any(), {
410
+ decode: (val) => (val instanceof Principal ? val.toText() : val),
411
+ encode: (val) =>
412
+ typeof val === "string" ? Principal.fromText(val) : val,
413
+ })
414
+ }
415
+ }