@ic-reactor/core 3.0.3-beta.4 → 3.0.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 +6 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -3
- package/dist/client.js.map +1 -1
- package/dist/display/types.d.ts +4 -2
- package/dist/display/types.d.ts.map +1 -1
- package/dist/display/visitor.d.ts +2 -1
- package/dist/display/visitor.d.ts.map +1 -1
- package/dist/display/visitor.js +146 -121
- package/dist/display/visitor.js.map +1 -1
- package/dist/display-reactor.d.ts +9 -41
- package/dist/display-reactor.d.ts.map +1 -1
- package/dist/display-reactor.js +5 -41
- package/dist/display-reactor.js.map +1 -1
- package/dist/reactor.d.ts +17 -1
- package/dist/reactor.d.ts.map +1 -1
- package/dist/reactor.js +60 -44
- package/dist/reactor.js.map +1 -1
- package/dist/types/display-reactor.d.ts +2 -2
- package/dist/types/display-reactor.d.ts.map +1 -1
- package/dist/types/reactor.d.ts +8 -9
- package/dist/types/reactor.d.ts.map +1 -1
- package/dist/types/transform.d.ts +1 -1
- package/dist/types/transform.d.ts.map +1 -1
- package/dist/utils/helper.d.ts +20 -1
- package/dist/utils/helper.d.ts.map +1 -1
- package/dist/utils/helper.js +37 -6
- package/dist/utils/helper.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/zod.d.ts +34 -0
- package/dist/utils/zod.d.ts.map +1 -0
- package/dist/utils/zod.js +39 -0
- package/dist/utils/zod.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -1
- package/dist/version.js.map +1 -1
- package/package.json +7 -6
- package/src/client.ts +571 -0
- package/src/display/helper.ts +92 -0
- package/src/display/index.ts +3 -0
- package/src/display/types.ts +91 -0
- package/src/display/visitor.ts +415 -0
- package/src/display-reactor.ts +361 -0
- package/src/errors/index.ts +246 -0
- package/src/index.ts +8 -0
- package/src/reactor.ts +461 -0
- package/src/types/client.ts +110 -0
- package/src/types/display-reactor.ts +73 -0
- package/src/types/index.ts +6 -0
- package/src/types/reactor.ts +188 -0
- package/src/types/result.ts +50 -0
- package/src/types/transform.ts +29 -0
- package/src/types/variant.ts +39 -0
- package/src/utils/agent.ts +201 -0
- package/src/utils/candid.ts +112 -0
- package/src/utils/constants.ts +12 -0
- package/src/utils/helper.ts +155 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/polling.ts +330 -0
- package/src/utils/zod.ts +56 -0
- package/src/version.ts +5 -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 any[]
|
|
73
|
+
? { [K in keyof T]: DisplayOf<T[K]> }
|
|
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
|
+
}
|