@provablehq/veil-codegen 0.4.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.
- package/LICENSE +21 -0
- package/README.md +104 -0
- package/dist/chunk-OU67QL3U.js +493 -0
- package/dist/chunk-OU67QL3U.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +71 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Provable Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# @provablehq/veil-codegen
|
|
2
|
+
|
|
3
|
+
Generates TypeScript bindings from an Aleo program's ABI, and ships the
|
|
4
|
+
`veil-codegen` CLI that drives it.
|
|
5
|
+
|
|
6
|
+
Reach for it as a package maintainer, not a consumer: point it at a program's
|
|
7
|
+
`abi.json` and it emits a `.ts` module of struct and record interfaces, record
|
|
8
|
+
and struct decoders (`RecordValue` → typed interface), per-function input and
|
|
9
|
+
output types, mapping and storage types, the parsed `PROGRAM_ABI` constant, and
|
|
10
|
+
a typed contract factory (`read`/`write`/`simulate`/`execute`). A package like
|
|
11
|
+
`@provablehq/shield-swap-sdk` commits that output and ships it — a consumer installing the
|
|
12
|
+
package gets the bindings already. You run codegen when the upstream contract
|
|
13
|
+
drifts (redeploy, a new or renamed entrypoint, struct, or mapping) and the
|
|
14
|
+
checked-in bindings need to catch up.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
It is a build-time tool, so install it as a dev dependency:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
pnpm add -D @provablehq/veil-codegen
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### CLI
|
|
27
|
+
|
|
28
|
+
Two modes. Generate one file directly with `--abi` + `--out`:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
veil-codegen --abi ./abi/loyalty_token.json --out ./src/generated/loyalty_token.ts
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or drive one or more programs from a config file with `--config` (this is how
|
|
35
|
+
`@provablehq/shield-swap-sdk` wires it — a `generate` script runs
|
|
36
|
+
`veil-codegen --config codegen/veil.config.json`):
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
veil-codegen --config veil.config.json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Flags:
|
|
43
|
+
|
|
44
|
+
- `--abi <path>` — path to the program's `abi.json`. Pair with `--out`.
|
|
45
|
+
- `--out <path>` — output `.ts` file. Parent directories are created if missing.
|
|
46
|
+
- `--config <path>` — path to a config JSON. Defaults to `veil.config.json`.
|
|
47
|
+
- `--core-import <path>` — import specifier for `@provablehq/veil-core` in the emitted
|
|
48
|
+
file. Defaults to `@provablehq/veil-core`; on the CLI it overrides the config's
|
|
49
|
+
`coreImport`.
|
|
50
|
+
- `--help`, `-h` — print usage.
|
|
51
|
+
|
|
52
|
+
Paths inside a config file resolve relative to the config file's own location,
|
|
53
|
+
not the working directory.
|
|
54
|
+
|
|
55
|
+
### Config file
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"programs": [
|
|
60
|
+
{
|
|
61
|
+
"abi": "./abi/shield_swap_v0_0_2.json",
|
|
62
|
+
"out": "../src/generated/shield_swap.ts"
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
"coreImport": "@provablehq/veil-core"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- `programs` — one entry per program to generate. Each has an `abi` path and an
|
|
70
|
+
`out` path, both resolved relative to the config file.
|
|
71
|
+
- `programs[].programId` — optional. Stamps a `PROGRAM_ID` (and factory target)
|
|
72
|
+
that differs from the ABI's own `program`. Set it when the bindings take their
|
|
73
|
+
shape from one deployment's ABI but must target another, identical-shape
|
|
74
|
+
deployment. Defaults to the ABI's `program`.
|
|
75
|
+
- `coreImport` — optional. Import specifier for `@provablehq/veil-core` in every emitted
|
|
76
|
+
file. Defaults to `@provablehq/veil-core`.
|
|
77
|
+
|
|
78
|
+
### Programmatic API
|
|
79
|
+
|
|
80
|
+
`generate` takes an already-parsed ABI and returns the TypeScript source as a
|
|
81
|
+
string; it writes nothing and touches no network. Parse the ABI with
|
|
82
|
+
`parseAbi` from `@provablehq/veil-core` first, then write the result yourself. This is the
|
|
83
|
+
path to take when you generate as part of a larger build step rather than from
|
|
84
|
+
the CLI.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { readFileSync, writeFileSync } from 'node:fs'
|
|
88
|
+
import { parseAbi } from '@provablehq/veil-core'
|
|
89
|
+
import { generate } from '@provablehq/veil-codegen'
|
|
90
|
+
|
|
91
|
+
const abi = parseAbi(JSON.parse(readFileSync('./abi/loyalty_token.json', 'utf-8')))
|
|
92
|
+
const source = generate({ abi, coreImport: '@provablehq/veil-core' })
|
|
93
|
+
writeFileSync('./src/generated/loyalty_token.ts', source)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`generate(options)` accepts `GenerateOptions`:
|
|
97
|
+
|
|
98
|
+
- `abi` — the parsed `ABI` to generate from.
|
|
99
|
+
- `coreImport` — optional import specifier for `@provablehq/veil-core`. Defaults to
|
|
100
|
+
`@provablehq/veil-core`.
|
|
101
|
+
- `programId` — optional override for the emitted `PROGRAM_ID`, same meaning as
|
|
102
|
+
the config field above. Defaults to the ABI's `program`.
|
|
103
|
+
</content>
|
|
104
|
+
</invoke>
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
// src/generate.ts
|
|
2
|
+
function generate(options) {
|
|
3
|
+
const { abi, coreImport = "@provablehq/veil-core", programId = abi.program } = options;
|
|
4
|
+
const lines = [];
|
|
5
|
+
lines.push(`// Auto-generated by @provablehq/veil-codegen from ${abi.program}`);
|
|
6
|
+
lines.push(`// Do not edit manually.`);
|
|
7
|
+
lines.push("");
|
|
8
|
+
lines.push(`import { getContract } from '${coreImport}'`);
|
|
9
|
+
lines.push(`import type { RecordValue, FutureValue, PublicClient, WalletClient, ABI, InputRequest, PlaintextValue } from '${coreImport}'`);
|
|
10
|
+
lines.push("");
|
|
11
|
+
lines.push(`export const PROGRAM_ID = '${programId}' as const`);
|
|
12
|
+
lines.push("");
|
|
13
|
+
lines.push(`function litStr(v: PlaintextValue | undefined, suffix: string): string {`);
|
|
14
|
+
lines.push(` if (typeof v === 'bigint') return \`\${v}\${suffix}\``);
|
|
15
|
+
lines.push(` if (typeof v === 'string') return v`);
|
|
16
|
+
lines.push(` if (v == null) return ''`);
|
|
17
|
+
lines.push(` // Fail fast: a struct/array/boolean value in a literal slot means the ABI`);
|
|
18
|
+
lines.push(` // or an upstream parser is wrong \u2014 never coerce it into corrupt data.`);
|
|
19
|
+
lines.push(` throw new Error(\`Expected \${suffix} literal, got \${typeof v}\`)`);
|
|
20
|
+
lines.push(`}`);
|
|
21
|
+
lines.push("");
|
|
22
|
+
for (const struct of abi.structs) {
|
|
23
|
+
lines.push(...generateStructInterface(struct));
|
|
24
|
+
lines.push("");
|
|
25
|
+
lines.push(...generateStructMapper(struct));
|
|
26
|
+
lines.push("");
|
|
27
|
+
}
|
|
28
|
+
for (const record of abi.records) {
|
|
29
|
+
lines.push(...generateRecordInterface(record));
|
|
30
|
+
lines.push("");
|
|
31
|
+
lines.push(...generateRecordMapper(record));
|
|
32
|
+
lines.push("");
|
|
33
|
+
}
|
|
34
|
+
for (const fn of abi.functions) {
|
|
35
|
+
lines.push(...generateFunctionInputType(fn, abi));
|
|
36
|
+
lines.push("");
|
|
37
|
+
lines.push(...generateFunctionOutputType(fn, abi));
|
|
38
|
+
lines.push("");
|
|
39
|
+
}
|
|
40
|
+
for (const mapping of abi.mappings) {
|
|
41
|
+
lines.push(...generateMappingType(mapping));
|
|
42
|
+
lines.push("");
|
|
43
|
+
}
|
|
44
|
+
for (const sv of abi.storageVariables) {
|
|
45
|
+
lines.push(...generateStorageVariableType(sv));
|
|
46
|
+
lines.push("");
|
|
47
|
+
}
|
|
48
|
+
lines.push(...generateAbiConstant(abi));
|
|
49
|
+
lines.push("");
|
|
50
|
+
lines.push(...generateContractFactory(abi));
|
|
51
|
+
lines.push("");
|
|
52
|
+
return lines.join("\n");
|
|
53
|
+
}
|
|
54
|
+
function generateStructInterface(struct) {
|
|
55
|
+
const name = struct.path[struct.path.length - 1] ?? "UnknownStruct";
|
|
56
|
+
const lines = [];
|
|
57
|
+
lines.push(`export interface ${name} {`);
|
|
58
|
+
for (const field of struct.fields) {
|
|
59
|
+
const tsType = plaintextToTsType(field.type);
|
|
60
|
+
lines.push(` ${field.name}: ${tsType}`);
|
|
61
|
+
}
|
|
62
|
+
lines.push(`}`);
|
|
63
|
+
return lines;
|
|
64
|
+
}
|
|
65
|
+
function generateRecordInterface(record) {
|
|
66
|
+
const name = recordName(record);
|
|
67
|
+
const lines = [];
|
|
68
|
+
lines.push(`export interface ${name} {`);
|
|
69
|
+
lines.push(` owner: string`);
|
|
70
|
+
for (const field of record.fields) {
|
|
71
|
+
if (field.name === "owner") continue;
|
|
72
|
+
const tsType = plaintextToTsType(field.type);
|
|
73
|
+
lines.push(` ${field.name}: ${tsType}`);
|
|
74
|
+
}
|
|
75
|
+
lines.push(` _record: RecordValue`);
|
|
76
|
+
lines.push(`}`);
|
|
77
|
+
return lines;
|
|
78
|
+
}
|
|
79
|
+
function mapperFieldLines(fields, container, fieldsVar) {
|
|
80
|
+
const lines = [];
|
|
81
|
+
for (const field of fields) {
|
|
82
|
+
if (field.name === "owner") continue;
|
|
83
|
+
if (field.type.kind === "struct") {
|
|
84
|
+
const structName = field.type.path.at(-1);
|
|
85
|
+
if (!structName) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Malformed ABI: struct field "${field.name}" in "${container}" has an empty type path. Cannot derive struct name for code generation.`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
lines.push(` ${field.name}: ${fieldsVar}.${field.name}?.value as unknown as ${structName} ?? {} as unknown as ${structName},`);
|
|
91
|
+
} else {
|
|
92
|
+
const rawAccess = `${fieldsVar}.${field.name}?.value`;
|
|
93
|
+
const expr = plaintextFieldExpr(rawAccess, field.type);
|
|
94
|
+
lines.push(` ${field.name}: ${expr} ?? ${plaintextDefault(field.type)},`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return lines;
|
|
98
|
+
}
|
|
99
|
+
function fieldsGuardLine(varName) {
|
|
100
|
+
return ` const fields = (typeof ${varName} === 'object' && ${varName} !== null ? ${varName}.fields : undefined) ?? {}`;
|
|
101
|
+
}
|
|
102
|
+
function generateRecordMapper(record) {
|
|
103
|
+
const name = recordName(record);
|
|
104
|
+
const lines = [];
|
|
105
|
+
lines.push(`export function to${name}(record: RecordValue | string): ${name} {`);
|
|
106
|
+
lines.push(fieldsGuardLine("record"));
|
|
107
|
+
lines.push(` return {`);
|
|
108
|
+
lines.push(` owner: ((typeof record === 'object' && record !== null ? record.owner : undefined) ?? '') as string,`);
|
|
109
|
+
lines.push(...mapperFieldLines(record.fields, name, "fields"));
|
|
110
|
+
lines.push(` _record: record as unknown as RecordValue,`);
|
|
111
|
+
lines.push(` }`);
|
|
112
|
+
lines.push(`}`);
|
|
113
|
+
return lines;
|
|
114
|
+
}
|
|
115
|
+
function generateStructMapper(struct) {
|
|
116
|
+
const name = struct.path[struct.path.length - 1] ?? "UnknownStruct";
|
|
117
|
+
const lines = [];
|
|
118
|
+
lines.push(`export function to${name}(value: RecordValue): ${name} {`);
|
|
119
|
+
lines.push(` return {`);
|
|
120
|
+
lines.push(...mapperFieldLines(struct.fields, name, "value.fields"));
|
|
121
|
+
lines.push(` }`);
|
|
122
|
+
lines.push(`}`);
|
|
123
|
+
return lines;
|
|
124
|
+
}
|
|
125
|
+
function generateFunctionInputType(fn, abi) {
|
|
126
|
+
const typeName = pascalCase(fn.name) + "Inputs";
|
|
127
|
+
const lines = [];
|
|
128
|
+
lines.push(`export type ${typeName} = {`);
|
|
129
|
+
for (const input of fn.inputs) {
|
|
130
|
+
const name = input.name ?? `arg${fn.inputs.indexOf(input)}`;
|
|
131
|
+
if (input.type.kind === "plaintext") {
|
|
132
|
+
const tsType = plaintextToTsType(input.type.type);
|
|
133
|
+
lines.push(` ${name}: ${tsType} | InputRequest`);
|
|
134
|
+
} else if (input.type.kind === "record") {
|
|
135
|
+
const recName = input.type.path[input.type.path.length - 1] ?? "RecordValue";
|
|
136
|
+
const isLocal = !input.type.program || input.type.program.replace(/\.aleo$/, "") === abi.program.replace(/\.aleo$/, "");
|
|
137
|
+
lines.push(` ${name}: ${isLocal ? recName : "RecordValue"} | RecordValue | string | InputRequest`);
|
|
138
|
+
} else if (input.type.kind === "dynamicRecord") {
|
|
139
|
+
lines.push(` ${name}: RecordValue | string | InputRequest`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
lines.push(`}`);
|
|
143
|
+
return lines;
|
|
144
|
+
}
|
|
145
|
+
function generateFunctionOutputType(fn, abi) {
|
|
146
|
+
const typeName = pascalCase(fn.name) + "Outputs";
|
|
147
|
+
const lines = [];
|
|
148
|
+
if (fn.outputs.length === 0) {
|
|
149
|
+
lines.push(`export type ${typeName} = void`);
|
|
150
|
+
return lines;
|
|
151
|
+
}
|
|
152
|
+
if (fn.outputs.length === 1) {
|
|
153
|
+
const tsType = outputToTsType(fn.outputs[0].type, abi);
|
|
154
|
+
lines.push(`export type ${typeName} = ${tsType}`);
|
|
155
|
+
return lines;
|
|
156
|
+
}
|
|
157
|
+
const typeElements = fn.outputs.map((output) => outputToTsType(output.type, abi));
|
|
158
|
+
lines.push(`export type ${typeName} = [${typeElements.join(", ")}]`);
|
|
159
|
+
return lines;
|
|
160
|
+
}
|
|
161
|
+
function outputToTsType(output, abi) {
|
|
162
|
+
if (output.kind === "plaintext") {
|
|
163
|
+
return plaintextToTsType(output.type);
|
|
164
|
+
} else if (output.kind === "record") {
|
|
165
|
+
const recName = output.path[output.path.length - 1] ?? "RecordValue";
|
|
166
|
+
const isLocal = !output.program || output.program.replace(/\.aleo$/, "") === abi.program.replace(/\.aleo$/, "");
|
|
167
|
+
return isLocal ? recName : "RecordValue";
|
|
168
|
+
} else if (output.kind === "dynamicRecord") {
|
|
169
|
+
return "RecordValue";
|
|
170
|
+
} else if (output.kind === "future" || output.kind === "dynamicFuture") {
|
|
171
|
+
return "FutureValue";
|
|
172
|
+
}
|
|
173
|
+
return "unknown";
|
|
174
|
+
}
|
|
175
|
+
function generateMappingType(mapping) {
|
|
176
|
+
const name = pascalCase(mapping.name);
|
|
177
|
+
const keyType = plaintextToTsType(mapping.key);
|
|
178
|
+
const valueType = plaintextToTsType(mapping.value);
|
|
179
|
+
return [
|
|
180
|
+
`export type ${name}MappingKey = ${keyType}`,
|
|
181
|
+
`export type ${name}MappingValue = ${valueType}`
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
function generateStorageVariableType(sv) {
|
|
185
|
+
const name = pascalCase(sv.name);
|
|
186
|
+
const tsType = storageTypeToTs(sv.type);
|
|
187
|
+
return [`export type ${name}StorageType = ${tsType}`];
|
|
188
|
+
}
|
|
189
|
+
function storageTypeToTs(st) {
|
|
190
|
+
if (st.kind === "plaintext") {
|
|
191
|
+
return plaintextToTsType(st.type);
|
|
192
|
+
} else if (st.kind === "vector") {
|
|
193
|
+
return `${storageTypeToTs(st.element)}[]`;
|
|
194
|
+
}
|
|
195
|
+
return "unknown";
|
|
196
|
+
}
|
|
197
|
+
function isSmallInt(p) {
|
|
198
|
+
return p === "u8" || p === "u16" || p === "u32" || p === "i8" || p === "i16" || p === "i32";
|
|
199
|
+
}
|
|
200
|
+
function plaintextToTsType(pt) {
|
|
201
|
+
switch (pt.kind) {
|
|
202
|
+
case "primitive":
|
|
203
|
+
return primitiveToTsType(pt.primitive);
|
|
204
|
+
case "array":
|
|
205
|
+
return `${plaintextToTsType(pt.element)}[]`;
|
|
206
|
+
case "struct":
|
|
207
|
+
return pt.path[pt.path.length - 1] ?? "unknown";
|
|
208
|
+
case "optional":
|
|
209
|
+
return `${plaintextToTsType(pt.inner)} | undefined`;
|
|
210
|
+
default:
|
|
211
|
+
return "unknown";
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function primitiveToTsType(p) {
|
|
215
|
+
if (isSmallInt(p)) return "number";
|
|
216
|
+
switch (p) {
|
|
217
|
+
case "address":
|
|
218
|
+
case "field":
|
|
219
|
+
case "group":
|
|
220
|
+
case "scalar":
|
|
221
|
+
case "signature":
|
|
222
|
+
case "identifier":
|
|
223
|
+
return "string";
|
|
224
|
+
case "boolean":
|
|
225
|
+
return "boolean";
|
|
226
|
+
// 64-bit and wider: must be bigint to avoid precision loss
|
|
227
|
+
case "u64":
|
|
228
|
+
case "u128":
|
|
229
|
+
case "i64":
|
|
230
|
+
case "i128":
|
|
231
|
+
return "bigint";
|
|
232
|
+
default:
|
|
233
|
+
return "unknown";
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function plaintextFieldExpr(rawAccess, pt) {
|
|
237
|
+
if (pt.kind !== "primitive") return rawAccess;
|
|
238
|
+
const p = pt.primitive;
|
|
239
|
+
if (isSmallInt(p)) return `Number((${rawAccess} ?? 0n) as bigint)`;
|
|
240
|
+
switch (p) {
|
|
241
|
+
// Wide integers stay bigint end-to-end.
|
|
242
|
+
case "u64":
|
|
243
|
+
case "u128":
|
|
244
|
+
case "i64":
|
|
245
|
+
case "i128":
|
|
246
|
+
return `${rawAccess} as bigint`;
|
|
247
|
+
// Literal types with a suffix: runtime parsers may deliver these as bigint
|
|
248
|
+
// (suffix stripped) or as the canonical suffixed string — normalize to the
|
|
249
|
+
// canonical string form (e.g. 123n → "123field").
|
|
250
|
+
case "field":
|
|
251
|
+
case "group":
|
|
252
|
+
case "scalar":
|
|
253
|
+
return `litStr(${rawAccess}, '${p}')`;
|
|
254
|
+
case "address":
|
|
255
|
+
case "signature":
|
|
256
|
+
case "identifier":
|
|
257
|
+
return `${rawAccess} as string`;
|
|
258
|
+
case "boolean":
|
|
259
|
+
return `${rawAccess} as boolean`;
|
|
260
|
+
default:
|
|
261
|
+
return rawAccess;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function plaintextDefault(pt) {
|
|
265
|
+
if (pt.kind !== "primitive") return "''";
|
|
266
|
+
if (isSmallInt(pt.primitive)) return "0";
|
|
267
|
+
switch (pt.primitive) {
|
|
268
|
+
case "boolean":
|
|
269
|
+
return "false";
|
|
270
|
+
// Wide integers — bigint default
|
|
271
|
+
case "u64":
|
|
272
|
+
case "u128":
|
|
273
|
+
case "i64":
|
|
274
|
+
case "i128":
|
|
275
|
+
return "0n";
|
|
276
|
+
case "field":
|
|
277
|
+
case "group":
|
|
278
|
+
case "scalar":
|
|
279
|
+
return "''";
|
|
280
|
+
case "address":
|
|
281
|
+
case "signature":
|
|
282
|
+
case "identifier":
|
|
283
|
+
return "''";
|
|
284
|
+
default:
|
|
285
|
+
return "''";
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function generateAbiConstant(abi) {
|
|
289
|
+
return [
|
|
290
|
+
`/** The parsed ABI for ${abi.program}. */`,
|
|
291
|
+
`export const PROGRAM_ABI: ABI = ${JSON.stringify(abi, null, 2)}`
|
|
292
|
+
];
|
|
293
|
+
}
|
|
294
|
+
function namedParamsType(fn, abi) {
|
|
295
|
+
if (fn.inputs.length === 0) return "{}";
|
|
296
|
+
const params = fn.inputs.map((input) => {
|
|
297
|
+
const name = input.name ?? `arg${fn.inputs.indexOf(input)}`;
|
|
298
|
+
let tsType;
|
|
299
|
+
if (input.type.kind === "plaintext") {
|
|
300
|
+
tsType = plaintextToTsType(input.type.type);
|
|
301
|
+
} else if (input.type.kind === "record") {
|
|
302
|
+
const recName = input.type.path[input.type.path.length - 1] ?? "RecordValue";
|
|
303
|
+
const isLocal = !input.type.program || input.type.program.replace(/\.aleo$/, "") === abi.program.replace(/\.aleo$/, "");
|
|
304
|
+
tsType = isLocal ? `${recName} | RecordValue | string` : "RecordValue | string";
|
|
305
|
+
} else {
|
|
306
|
+
tsType = "RecordValue | string";
|
|
307
|
+
}
|
|
308
|
+
return `${name}: ${tsType} | InputRequest`;
|
|
309
|
+
});
|
|
310
|
+
return `{ ${params.join(", ")} }`;
|
|
311
|
+
}
|
|
312
|
+
function simulateReturnType(fn, abi) {
|
|
313
|
+
if (fn.outputs.length === 0) return "void";
|
|
314
|
+
if (fn.outputs.length === 1) return outputToTsType(fn.outputs[0].type, abi);
|
|
315
|
+
return `[${fn.outputs.map((o) => outputToTsType(o.type, abi)).join(", ")}]`;
|
|
316
|
+
}
|
|
317
|
+
function executeReturnType(fn, abi) {
|
|
318
|
+
const simType = simulateReturnType(fn, abi);
|
|
319
|
+
if (simType === "void") return "{ transactionId: string }";
|
|
320
|
+
return `{ transactionId: string, result: ${simType} }`;
|
|
321
|
+
}
|
|
322
|
+
function inputNames(fn) {
|
|
323
|
+
return fn.inputs.map((input, i) => input.name ?? `arg${i}`);
|
|
324
|
+
}
|
|
325
|
+
function resolveRecordInputs(fn) {
|
|
326
|
+
const resolveLines = [];
|
|
327
|
+
const resolvedNames = [];
|
|
328
|
+
for (let i = 0; i < fn.inputs.length; i++) {
|
|
329
|
+
const input = fn.inputs[i];
|
|
330
|
+
const name = input.name ?? `arg${i}`;
|
|
331
|
+
if (input.type.kind === "record" || input.type.kind === "dynamicRecord") {
|
|
332
|
+
resolveLines.push(` const _${name} = ${name}?._record ?? ${name}`);
|
|
333
|
+
resolvedNames.push(`_${name}`);
|
|
334
|
+
} else {
|
|
335
|
+
resolvedNames.push(name);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return { resolveLines, resolvedNames };
|
|
339
|
+
}
|
|
340
|
+
function outputMapperExpr(output, i, abi) {
|
|
341
|
+
if (output.type.kind === "record") {
|
|
342
|
+
const recName = output.type.path[output.type.path.length - 1] ?? "";
|
|
343
|
+
const isLocal = !output.type.program || output.type.program.replace(/\.aleo$/, "") === abi.program.replace(/\.aleo$/, "");
|
|
344
|
+
if (isLocal && recName) {
|
|
345
|
+
return `to${recName}(result.outputs[${i}] as unknown as RecordValue)`;
|
|
346
|
+
}
|
|
347
|
+
return `result.outputs[${i}] as unknown as RecordValue`;
|
|
348
|
+
}
|
|
349
|
+
if (output.type.kind === "plaintext") {
|
|
350
|
+
return `result.outputs[${i}] as unknown as ${plaintextToTsType(output.type.type)}`;
|
|
351
|
+
}
|
|
352
|
+
if (output.type.kind === "future" || output.type.kind === "dynamicFuture") {
|
|
353
|
+
return `result.outputs[${i}] as unknown as FutureValue`;
|
|
354
|
+
}
|
|
355
|
+
return `result.outputs[${i}]`;
|
|
356
|
+
}
|
|
357
|
+
function generateContractFactory(abi) {
|
|
358
|
+
const programName = abi.program;
|
|
359
|
+
const factoryName = pascalCase(programName.replace(".aleo", ""));
|
|
360
|
+
const lines = [];
|
|
361
|
+
lines.push(`export interface ${factoryName}Contract {`);
|
|
362
|
+
lines.push(` program: string`);
|
|
363
|
+
lines.push(` abi: ABI`);
|
|
364
|
+
if (abi.mappings.length > 0) {
|
|
365
|
+
lines.push(` read: {`);
|
|
366
|
+
for (const mapping of abi.mappings) {
|
|
367
|
+
const keyType = plaintextToTsType(mapping.key);
|
|
368
|
+
lines.push(` ${mapping.name}: (params: { key: ${keyType} }) => Promise<unknown>`);
|
|
369
|
+
}
|
|
370
|
+
lines.push(` }`);
|
|
371
|
+
} else {
|
|
372
|
+
lines.push(` read: Record<string, (params: { key: string }) => Promise<unknown>>`);
|
|
373
|
+
}
|
|
374
|
+
if (abi.functions.length > 0) {
|
|
375
|
+
lines.push(` write: {`);
|
|
376
|
+
for (const fn of abi.functions) {
|
|
377
|
+
const params = namedParamsType(fn, abi);
|
|
378
|
+
lines.push(` ${fn.name}: (params: ${params}) => Promise<string>`);
|
|
379
|
+
}
|
|
380
|
+
lines.push(` }`);
|
|
381
|
+
}
|
|
382
|
+
if (abi.functions.length > 0) {
|
|
383
|
+
lines.push(` simulate: {`);
|
|
384
|
+
for (const fn of abi.functions) {
|
|
385
|
+
const params = namedParamsType(fn, abi);
|
|
386
|
+
const retType = simulateReturnType(fn, abi);
|
|
387
|
+
lines.push(` ${fn.name}: (params: ${params}) => Promise<${retType}>`);
|
|
388
|
+
}
|
|
389
|
+
lines.push(` }`);
|
|
390
|
+
}
|
|
391
|
+
if (abi.functions.length > 0) {
|
|
392
|
+
lines.push(` execute: {`);
|
|
393
|
+
for (const fn of abi.functions) {
|
|
394
|
+
const params = namedParamsType(fn, abi);
|
|
395
|
+
const retType = executeReturnType(fn, abi);
|
|
396
|
+
lines.push(` ${fn.name}: (params: ${params}) => Promise<${retType}>`);
|
|
397
|
+
}
|
|
398
|
+
lines.push(` }`);
|
|
399
|
+
}
|
|
400
|
+
lines.push(` fetchAbi: () => Promise<ABI>`);
|
|
401
|
+
lines.push(`}`);
|
|
402
|
+
lines.push("");
|
|
403
|
+
lines.push(`export function create${factoryName}Contract(options: {`);
|
|
404
|
+
lines.push(` publicClient?: PublicClient,`);
|
|
405
|
+
lines.push(` walletClient?: WalletClient,`);
|
|
406
|
+
lines.push(` programSource?: string,`);
|
|
407
|
+
lines.push(` imports?: Record<string, string>,`);
|
|
408
|
+
lines.push(`}): ${factoryName}Contract {`);
|
|
409
|
+
lines.push(` if (!options.publicClient && !options.walletClient) throw new Error('At least one of publicClient or walletClient is required')`);
|
|
410
|
+
lines.push(` const client = options.publicClient && options.walletClient`);
|
|
411
|
+
lines.push(` ? { public: options.publicClient, wallet: options.walletClient }`);
|
|
412
|
+
lines.push(` : (options.publicClient ?? options.walletClient)!`);
|
|
413
|
+
lines.push(` const raw = getContract({ program: PROGRAM_ID, abi: PROGRAM_ABI, client, programSource: options.programSource, imports: options.imports })`);
|
|
414
|
+
lines.push(` const _raw = raw as any`);
|
|
415
|
+
lines.push("");
|
|
416
|
+
lines.push(` return {`);
|
|
417
|
+
lines.push(` program: raw.program,`);
|
|
418
|
+
lines.push(` abi: raw.abi as ABI,`);
|
|
419
|
+
lines.push(` read: _raw.read as ${factoryName}Contract['read'],`);
|
|
420
|
+
if (abi.functions.length > 0) {
|
|
421
|
+
lines.push(` write: {`);
|
|
422
|
+
for (const fn of abi.functions) {
|
|
423
|
+
const names = inputNames(fn);
|
|
424
|
+
const { resolveLines, resolvedNames } = resolveRecordInputs(fn);
|
|
425
|
+
lines.push(` ${fn.name}: (params: any) => {`);
|
|
426
|
+
if (names.length > 0) lines.push(` const { ${names.join(", ")} } = params`);
|
|
427
|
+
for (const line of resolveLines) lines.push(line);
|
|
428
|
+
lines.push(` return _raw.write.${fn.name}({ inputs: [${resolvedNames.join(", ")}] })`);
|
|
429
|
+
lines.push(` },`);
|
|
430
|
+
}
|
|
431
|
+
lines.push(` },`);
|
|
432
|
+
}
|
|
433
|
+
if (abi.functions.length > 0) {
|
|
434
|
+
lines.push(` simulate: {`);
|
|
435
|
+
for (const fn of abi.functions) {
|
|
436
|
+
const names = inputNames(fn);
|
|
437
|
+
const { resolveLines, resolvedNames } = resolveRecordInputs(fn);
|
|
438
|
+
lines.push(` ${fn.name}: async (params: any) => {`);
|
|
439
|
+
if (names.length > 0) lines.push(` const { ${names.join(", ")} } = params`);
|
|
440
|
+
for (const line of resolveLines) lines.push(line);
|
|
441
|
+
if (fn.outputs.length === 0) {
|
|
442
|
+
lines.push(` await _raw.simulate.${fn.name}({ inputs: [${resolvedNames.join(", ")}] })`);
|
|
443
|
+
} else {
|
|
444
|
+
lines.push(` const result = await _raw.simulate.${fn.name}({ inputs: [${resolvedNames.join(", ")}] })`);
|
|
445
|
+
}
|
|
446
|
+
if (fn.outputs.length === 0) {
|
|
447
|
+
} else if (fn.outputs.length === 1) {
|
|
448
|
+
lines.push(` return ${outputMapperExpr(fn.outputs[0], 0, abi)}`);
|
|
449
|
+
} else {
|
|
450
|
+
const mappers = fn.outputs.map((o, i) => outputMapperExpr(o, i, abi));
|
|
451
|
+
lines.push(` return [${mappers.join(", ")}] as const`);
|
|
452
|
+
}
|
|
453
|
+
lines.push(` },`);
|
|
454
|
+
}
|
|
455
|
+
lines.push(` },`);
|
|
456
|
+
}
|
|
457
|
+
if (abi.functions.length > 0) {
|
|
458
|
+
lines.push(` execute: {`);
|
|
459
|
+
for (const fn of abi.functions) {
|
|
460
|
+
const names = inputNames(fn);
|
|
461
|
+
const { resolveLines, resolvedNames } = resolveRecordInputs(fn);
|
|
462
|
+
lines.push(` ${fn.name}: async (params: any) => {`);
|
|
463
|
+
if (names.length > 0) lines.push(` const { ${names.join(", ")} } = params`);
|
|
464
|
+
for (const line of resolveLines) lines.push(line);
|
|
465
|
+
lines.push(` const result = await _raw.execute.${fn.name}({ inputs: [${resolvedNames.join(", ")}] })`);
|
|
466
|
+
if (fn.outputs.length === 0) {
|
|
467
|
+
lines.push(` return { transactionId: result.transactionId }`);
|
|
468
|
+
} else if (fn.outputs.length === 1) {
|
|
469
|
+
lines.push(` return { transactionId: result.transactionId, result: ${outputMapperExpr(fn.outputs[0], 0, abi)} }`);
|
|
470
|
+
} else {
|
|
471
|
+
const mappers = fn.outputs.map((o, i) => outputMapperExpr(o, i, abi));
|
|
472
|
+
lines.push(` return { transactionId: result.transactionId, result: [${mappers.join(", ")}] as const }`);
|
|
473
|
+
}
|
|
474
|
+
lines.push(` },`);
|
|
475
|
+
}
|
|
476
|
+
lines.push(` },`);
|
|
477
|
+
}
|
|
478
|
+
lines.push(` fetchAbi: _raw.fetchAbi as unknown as ${factoryName}Contract['fetchAbi'],`);
|
|
479
|
+
lines.push(` }`);
|
|
480
|
+
lines.push(`}`);
|
|
481
|
+
return lines;
|
|
482
|
+
}
|
|
483
|
+
function recordName(record) {
|
|
484
|
+
return record.path[record.path.length - 1] ?? "UnknownRecord";
|
|
485
|
+
}
|
|
486
|
+
function pascalCase(s) {
|
|
487
|
+
return s.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export {
|
|
491
|
+
generate
|
|
492
|
+
};
|
|
493
|
+
//# sourceMappingURL=chunk-OU67QL3U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/generate.ts"],"sourcesContent":["// Code generator — reads a parsed ABI and produces TypeScript source code.\n\nimport type { ABI, RecordDef, StructDef, AbiFunction, Mapping, StorageVariable, StorageType } from '@provablehq/veil-core'\nimport type { Plaintext, Primitive } from '@provablehq/veil-core'\n\n// ── Public API ────────────────────────────────────────────────────────\n\n/**\n * Options for {@link generate}.\n *\n * @property abi Parsed ABI the bindings are generated from — it supplies the\n * structs, records, functions, mappings, and storage variables to emit.\n * @property coreImport Import path emitted for `@provablehq/veil-core` types. Defaults to\n * `'@provablehq/veil-core'`. Override when the generated file resolves core through an\n * alias or a relative path (e.g. inside the monorepo).\n * @property programId Program id to stamp into the emitted `PROGRAM_ID` and\n * the generated contract factory. Defaults to the ABI's own `program`.\n * Override when the bindings' shape is taken from one deployment's ABI but\n * they target another — e.g. when a newer program version's ABI is the only\n * one current tooling can parse, yet the live deployment (identical shape)\n * has a different id.\n */\nexport interface GenerateOptions {\n abi: ABI\n coreImport?: string\n programId?: string\n}\n\n/**\n * Generates TypeScript source code from an Aleo program ABI.\n *\n * Produces:\n * - Struct interfaces\n * - Record interfaces with correctly typed fields\n * - Record mapper functions (RecordValue → typed interface)\n * - Function input and output types\n * - Mapping key/value types\n * - Storage variable types\n */\nexport function generate(options: GenerateOptions): string {\n const { abi, coreImport = '@provablehq/veil-core', programId = abi.program } = options\n const lines: string[] = []\n\n // Header\n lines.push(`// Auto-generated by @provablehq/veil-codegen from ${abi.program}`)\n lines.push(`// Do not edit manually.`)\n lines.push('')\n lines.push(`import { getContract } from '${coreImport}'`)\n lines.push(`import type { RecordValue, FutureValue, PublicClient, WalletClient, ABI, InputRequest, PlaintextValue } from '${coreImport}'`)\n lines.push('')\n\n // Program ID constant — the program these bindings target (see programId option).\n lines.push(`export const PROGRAM_ID = '${programId}' as const`)\n lines.push('')\n\n // Decoder helper: literal types (field/group/scalar) may arrive from runtime\n // parsers as bigint (suffix stripped) or as the canonical suffixed string.\n // Normalize to the canonical string form so decoded objects match the\n // generated interfaces at runtime.\n lines.push(`function litStr(v: PlaintextValue | undefined, suffix: string): string {`)\n lines.push(` if (typeof v === 'bigint') return \\`\\${v}\\${suffix}\\``)\n lines.push(` if (typeof v === 'string') return v`)\n lines.push(` if (v == null) return ''`)\n lines.push(` // Fail fast: a struct/array/boolean value in a literal slot means the ABI`)\n lines.push(` // or an upstream parser is wrong — never coerce it into corrupt data.`)\n lines.push(` throw new Error(\\`Expected \\${suffix} literal, got \\${typeof v}\\`)`)\n lines.push(`}`)\n lines.push('')\n\n // Structs\n for (const struct of abi.structs) {\n lines.push(...generateStructInterface(struct))\n lines.push('')\n lines.push(...generateStructMapper(struct))\n lines.push('')\n }\n\n // Records\n for (const record of abi.records) {\n lines.push(...generateRecordInterface(record))\n lines.push('')\n lines.push(...generateRecordMapper(record))\n lines.push('')\n }\n\n // Function input + output types\n for (const fn of abi.functions) {\n lines.push(...generateFunctionInputType(fn, abi))\n lines.push('')\n lines.push(...generateFunctionOutputType(fn, abi))\n lines.push('')\n }\n\n // Mapping types\n for (const mapping of abi.mappings) {\n lines.push(...generateMappingType(mapping))\n lines.push('')\n }\n\n // Storage variable types\n for (const sv of abi.storageVariables) {\n lines.push(...generateStorageVariableType(sv))\n lines.push('')\n }\n\n // ABI constant + contract factory\n lines.push(...generateAbiConstant(abi))\n lines.push('')\n lines.push(...generateContractFactory(abi))\n lines.push('')\n\n return lines.join('\\n')\n}\n\n// ── Struct generation ─────────────────────────────────────────────────\n\nfunction generateStructInterface(struct: StructDef): string[] {\n const name = struct.path[struct.path.length - 1] ?? 'UnknownStruct'\n const lines: string[] = []\n\n lines.push(`export interface ${name} {`)\n\n for (const field of struct.fields) {\n const tsType = plaintextToTsType(field.type)\n lines.push(` ${field.name}: ${tsType}`)\n }\n\n lines.push(`}`)\n return lines\n}\n\n// ── Record generation ─────────────────────────────────────────────────\n\nfunction generateRecordInterface(record: RecordDef): string[] {\n const name = recordName(record)\n const lines: string[] = []\n\n lines.push(`export interface ${name} {`)\n lines.push(` owner: string`)\n\n for (const field of record.fields) {\n if (field.name === 'owner') continue\n const tsType = plaintextToTsType(field.type)\n lines.push(` ${field.name}: ${tsType}`)\n }\n\n // Carry the underlying RecordValue so typed records can be passed back as inputs\n lines.push(` _record: RecordValue`)\n lines.push(`}`)\n return lines\n}\n\n// Emit the `field: <converted value>` lines shared by record and struct mappers.\n// `varName` is the mapper's parameter name (the value being decoded); `container`\n// names the enclosing type for error messages.\nfunction mapperFieldLines(\n fields: readonly { name: string; type: Plaintext }[],\n container: string,\n fieldsVar: string,\n): string[] {\n const lines: string[] = []\n for (const field of fields) {\n if (field.name === 'owner') continue\n // Struct-typed fields: the raw PlaintextValue is a StructValue at runtime.\n // Cast through unknown to the generated struct interface so the return type\n // is correct. A missing field falls back to an empty object cast the same way.\n if (field.type.kind === 'struct') {\n const structName = field.type.path.at(-1)\n if (!structName) {\n throw new Error(\n `Malformed ABI: struct field \"${field.name}\" in \"${container}\" has an empty type path. ` +\n `Cannot derive struct name for code generation.`\n )\n }\n lines.push(` ${field.name}: ${fieldsVar}.${field.name}?.value as unknown as ${structName} ?? {} as unknown as ${structName},`)\n } else {\n const rawAccess = `${fieldsVar}.${field.name}?.value`\n const expr = plaintextFieldExpr(rawAccess, field.type)\n lines.push(` ${field.name}: ${expr} ?? ${plaintextDefault(field.type)},`)\n }\n }\n return lines\n}\n\n/**\n * Emits a `const fields = …` guard so a mapper tolerates an undecryptable\n * output. Record outputs owned by another party (e.g. a compliance record\n * minted to an authority) arrive as ciphertext strings, and every record\n * output arrives as ciphertext on the wallet path — the mapper then returns\n * defaulted fields with the raw ciphertext preserved on `_record`, rather\n * than dereferencing `.fields` on a string and throwing.\n */\nfunction fieldsGuardLine(varName: string): string {\n return ` const fields = (typeof ${varName} === 'object' && ${varName} !== null ? ${varName}.fields : undefined) ?? {}`\n}\n\nfunction generateRecordMapper(record: RecordDef): string[] {\n const name = recordName(record)\n const lines: string[] = []\n\n // Accepts a ciphertext string for records the caller cannot decrypt.\n lines.push(`export function to${name}(record: RecordValue | string): ${name} {`)\n lines.push(fieldsGuardLine('record'))\n lines.push(` return {`)\n lines.push(` owner: ((typeof record === 'object' && record !== null ? record.owner : undefined) ?? '') as string,`)\n lines.push(...mapperFieldLines(record.fields, name, 'fields'))\n lines.push(` _record: record as unknown as RecordValue,`)\n lines.push(` }`)\n lines.push(`}`)\n return lines\n}\n\n// Decoder for a struct (e.g. a mapping value like PoolState/Slot). Same per-field\n// width conversions as records, without the record-only `owner`/`_record` fields.\nfunction generateStructMapper(struct: StructDef): string[] {\n const name = struct.path[struct.path.length - 1] ?? 'UnknownStruct'\n const lines: string[] = []\n\n // Struct values (mapping reads, nested struct fields) are always readable\n // plaintext — never ciphertext — so no tolerance guard: a shape mismatch\n // should still fail loudly rather than return a silently-zeroed struct.\n lines.push(`export function to${name}(value: RecordValue): ${name} {`)\n lines.push(` return {`)\n lines.push(...mapperFieldLines(struct.fields, name, 'value.fields'))\n lines.push(` }`)\n lines.push(`}`)\n return lines\n}\n\n// ── Function input generation ─────────────────────────────────────────\n\nfunction generateFunctionInputType(fn: AbiFunction, abi: ABI): string[] {\n const typeName = pascalCase(fn.name) + 'Inputs'\n const lines: string[] = []\n\n lines.push(`export type ${typeName} = {`)\n\n for (const input of fn.inputs) {\n const name = input.name ?? `arg${fn.inputs.indexOf(input)}`\n\n // Every input slot also accepts an InputRequest — a privacy-preserving\n // wallet fulfils it (address injection, record selection, derived value).\n if (input.type.kind === 'plaintext') {\n const tsType = plaintextToTsType(input.type.type)\n lines.push(` ${name}: ${tsType} | InputRequest`)\n } else if (input.type.kind === 'record') {\n const recName = input.type.path[input.type.path.length - 1] ?? 'RecordValue'\n const isLocal = !input.type.program || input.type.program.replace(/\\.aleo$/, '') === abi.program.replace(/\\.aleo$/, '')\n lines.push(` ${name}: ${isLocal ? recName : 'RecordValue'} | RecordValue | string | InputRequest`)\n } else if (input.type.kind === 'dynamicRecord') {\n lines.push(` ${name}: RecordValue | string | InputRequest`)\n }\n }\n\n lines.push(`}`)\n return lines\n}\n\n// ── Function output generation ────────────────────────────────────────\n\nfunction generateFunctionOutputType(fn: AbiFunction, abi: ABI): string[] {\n const typeName = pascalCase(fn.name) + 'Outputs'\n const lines: string[] = []\n\n if (fn.outputs.length === 0) {\n lines.push(`export type ${typeName} = void`)\n return lines\n }\n\n if (fn.outputs.length === 1) {\n const tsType = outputToTsType(fn.outputs[0].type, abi)\n lines.push(`export type ${typeName} = ${tsType}`)\n return lines\n }\n\n const typeElements = fn.outputs.map((output) => outputToTsType(output.type, abi))\n lines.push(`export type ${typeName} = [${typeElements.join(', ')}]`)\n return lines\n}\n\nfunction outputToTsType(output: AbiFunction['outputs'][number]['type'], abi: ABI): string {\n if (output.kind === 'plaintext') {\n return plaintextToTsType(output.type)\n } else if (output.kind === 'record') {\n const recName = output.path[output.path.length - 1] ?? 'RecordValue'\n const isLocal = !output.program || output.program.replace(/\\.aleo$/, '') === abi.program.replace(/\\.aleo$/, '')\n return isLocal ? recName : 'RecordValue'\n } else if (output.kind === 'dynamicRecord') {\n return 'RecordValue'\n } else if (output.kind === 'future' || output.kind === 'dynamicFuture') {\n return 'FutureValue'\n }\n return 'unknown'\n}\n\n// ── Mapping generation ────────────────────────────────────────────────\n\nfunction generateMappingType(mapping: Mapping): string[] {\n const name = pascalCase(mapping.name)\n const keyType = plaintextToTsType(mapping.key)\n const valueType = plaintextToTsType(mapping.value)\n\n return [\n `export type ${name}MappingKey = ${keyType}`,\n `export type ${name}MappingValue = ${valueType}`,\n ]\n}\n\n// ── Storage variable generation ───────────────────────────────────────\n\nfunction generateStorageVariableType(sv: StorageVariable): string[] {\n const name = pascalCase(sv.name)\n const tsType = storageTypeToTs(sv.type)\n\n return [`export type ${name}StorageType = ${tsType}`]\n}\n\nfunction storageTypeToTs(st: StorageType): string {\n if (st.kind === 'plaintext') {\n return plaintextToTsType(st.type)\n } else if (st.kind === 'vector') {\n return `${storageTypeToTs(st.element)}[]`\n }\n return 'unknown'\n}\n\n// ── Type mapping helpers ──────────────────────────────────────────────\n\n/**\n * Returns true for integer primitives that fit safely in a JS number (≤ 32-bit).\n *\n * u8/u16/u32 and i8/i16/i32 are typed as `number`; u64/u128 and i64/i128 require\n * `bigint` to avoid precision loss. This predicate is the single source of truth\n * for that boundary — all three type-mapping helpers delegate to it so that adding\n * a new width requires changing only this function.\n */\nfunction isSmallInt(p: Primitive): boolean {\n return p === 'u8' || p === 'u16' || p === 'u32' || p === 'i8' || p === 'i16' || p === 'i32'\n}\n\nfunction plaintextToTsType(pt: Plaintext): string {\n switch (pt.kind) {\n case 'primitive':\n return primitiveToTsType(pt.primitive)\n case 'array':\n return `${plaintextToTsType(pt.element)}[]`\n case 'struct':\n return pt.path[pt.path.length - 1] ?? 'unknown'\n case 'optional':\n return `${plaintextToTsType(pt.inner)} | undefined`\n default:\n return 'unknown'\n }\n}\n\nfunction primitiveToTsType(p: Primitive): string {\n if (isSmallInt(p)) return 'number'\n switch (p) {\n case 'address':\n case 'field':\n case 'group':\n case 'scalar':\n case 'signature':\n case 'identifier':\n return 'string'\n case 'boolean':\n return 'boolean'\n // 64-bit and wider: must be bigint to avoid precision loss\n case 'u64':\n case 'u128':\n case 'i64':\n case 'i128':\n return 'bigint'\n default:\n return 'unknown'\n }\n}\n\n/**\n * Builds the full typed expression for a primitive record field access.\n *\n * The raw value stored in RecordFieldValue is always a bigint for all integer\n * widths (parsed by core's parseValue). For u8/u16/u32 and i8/i16/i32 fields\n * (typed as `number`), the access is wrapped with Number() to convert at\n * runtime. For u64+ (typed as `bigint`), it is cast directly. For non-primitive types (array,\n * optional) the raw access is returned unchanged — those fall through to the\n * caller's existing handling.\n *\n * @param rawAccess - Expression yielding the raw PlaintextValue, e.g. `record.fields.x?.value`\n */\nfunction plaintextFieldExpr(rawAccess: string, pt: Plaintext): string {\n // TODO(follow-up): non-primitive record fields other than struct (i.e. `array`,\n // `optional`) are NOT yet handled and fall through to the raw expression.\n // This is a known gap — ABIs containing such fields will produce non-compiling\n // output. Implement `array` and `optional` handling before using codegen with\n // such ABIs.\n if (pt.kind !== 'primitive') return rawAccess\n const p = pt.primitive\n // Small integers stored as bigint at runtime, exposed as number in the interface.\n // The ?? 0n guard is inside the Number() call: Number(undefined) = NaN, and\n // NaN ?? 0 does NOT trigger (?? only catches null/undefined). Guarding before\n // Number() ensures a missing field correctly defaults to 0.\n if (isSmallInt(p)) return `Number((${rawAccess} ?? 0n) as bigint)`\n switch (p) {\n // Wide integers stay bigint end-to-end.\n case 'u64':\n case 'u128':\n case 'i64':\n case 'i128':\n return `${rawAccess} as bigint`\n // Literal types with a suffix: runtime parsers may deliver these as bigint\n // (suffix stripped) or as the canonical suffixed string — normalize to the\n // canonical string form (e.g. 123n → \"123field\").\n case 'field':\n case 'group':\n case 'scalar':\n return `litStr(${rawAccess}, '${p}')`\n case 'address':\n case 'signature':\n case 'identifier':\n return `${rawAccess} as string`\n case 'boolean':\n return `${rawAccess} as boolean`\n default:\n return rawAccess\n }\n}\n\nfunction plaintextDefault(pt: Plaintext): string {\n // TODO(follow-up): see plaintextFieldExpr for the known array/optional gap.\n // Non-primitive record fields fall through to \"''\" (empty string default).\n if (pt.kind !== 'primitive') return \"''\"\n if (isSmallInt(pt.primitive)) return '0'\n switch (pt.primitive) {\n case 'boolean':\n return 'false'\n // Wide integers — bigint default\n case 'u64': case 'u128': case 'i64': case 'i128':\n return '0n'\n case 'field': case 'group': case 'scalar':\n return \"''\"\n case 'address': case 'signature': case 'identifier':\n return \"''\"\n default:\n return \"''\"\n }\n}\n\n// ── ABI constant + contract factory ───────────────────────────────────\n\nfunction generateAbiConstant(abi: ABI): string[] {\n // Embed the already-parsed ABI as a typed constant.\n // This avoids a round-trip through parseAbi at runtime.\n return [\n `/** The parsed ABI for ${abi.program}. */`,\n `export const PROGRAM_ABI: ABI = ${JSON.stringify(abi, null, 2)}`,\n ]\n}\n\n/** Generate named param type string for a function's inputs */\nfunction namedParamsType(fn: AbiFunction, abi: ABI): string {\n if (fn.inputs.length === 0) return '{}'\n const params = fn.inputs.map((input) => {\n const name = input.name ?? `arg${fn.inputs.indexOf(input)}`\n let tsType: string\n if (input.type.kind === 'plaintext') {\n tsType = plaintextToTsType(input.type.type)\n } else if (input.type.kind === 'record') {\n const recName = input.type.path[input.type.path.length - 1] ?? 'RecordValue'\n const isLocal = !input.type.program || input.type.program.replace(/\\.aleo$/, '') === abi.program.replace(/\\.aleo$/, '')\n tsType = isLocal ? `${recName} | RecordValue | string` : 'RecordValue | string'\n } else {\n tsType = 'RecordValue | string'\n }\n // Also accept an InputRequest in every slot (wallet-fulfilled input).\n return `${name}: ${tsType} | InputRequest`\n })\n return `{ ${params.join(', ')} }`\n}\n\n/** Generate the typed return type for simulate */\nfunction simulateReturnType(fn: AbiFunction, abi: ABI): string {\n if (fn.outputs.length === 0) return 'void'\n if (fn.outputs.length === 1) return outputToTsType(fn.outputs[0].type, abi)\n return `[${fn.outputs.map((o) => outputToTsType(o.type, abi)).join(', ')}]`\n}\n\n/** Generate the typed return type for execute (includes transactionId) */\nfunction executeReturnType(fn: AbiFunction, abi: ABI): string {\n const simType = simulateReturnType(fn, abi)\n if (simType === 'void') return '{ transactionId: string }'\n return `{ transactionId: string, result: ${simType} }`\n}\n\n/** Generate the input names array for converting named params to positional */\nfunction inputNames(fn: AbiFunction): string[] {\n return fn.inputs.map((input, i) => input.name ?? `arg${i}`)\n}\n\n/**\n * For record inputs, generate resolution lines that extract _record from typed records.\n * Returns { resolveLines: string[], resolvedNames: string[] }.\n * resolvedNames replaces record input names with their resolved versions.\n */\nfunction resolveRecordInputs(fn: AbiFunction): { resolveLines: string[], resolvedNames: string[] } {\n const resolveLines: string[] = []\n const resolvedNames: string[] = []\n\n for (let i = 0; i < fn.inputs.length; i++) {\n const input = fn.inputs[i]\n const name = input.name ?? `arg${i}`\n\n if (input.type.kind === 'record' || input.type.kind === 'dynamicRecord') {\n resolveLines.push(` const _${name} = ${name}?._record ?? ${name}`)\n resolvedNames.push(`_${name}`)\n } else {\n resolvedNames.push(name)\n }\n }\n\n return { resolveLines, resolvedNames }\n}\n\n/** Generate output mapper expression for a single output at index i */\nfunction outputMapperExpr(output: AbiFunction['outputs'][number], i: number, abi: ABI): string {\n if (output.type.kind === 'record') {\n const recName = output.type.path[output.type.path.length - 1] ?? ''\n const isLocal = !output.type.program || output.type.program.replace(/\\.aleo$/, '') === abi.program.replace(/\\.aleo$/, '')\n // Double-cast through unknown: result.outputs[i] is ParsedOutput | undefined under\n // noUncheckedIndexedAccess. The cast to unknown then to RecordValue is intentional —\n // the ABI guarantees this output is a record at this position.\n if (isLocal && recName) {\n return `to${recName}(result.outputs[${i}] as unknown as RecordValue)`\n }\n return `result.outputs[${i}] as unknown as RecordValue`\n }\n if (output.type.kind === 'plaintext') {\n return `result.outputs[${i}] as unknown as ${plaintextToTsType(output.type.type)}`\n }\n if (output.type.kind === 'future' || output.type.kind === 'dynamicFuture') {\n return `result.outputs[${i}] as unknown as FutureValue`\n }\n return `result.outputs[${i}]`\n}\n\nfunction generateContractFactory(abi: ABI): string[] {\n const programName = abi.program\n const factoryName = pascalCase(programName.replace('.aleo', ''))\n const lines: string[] = []\n\n // Generate typed interface with named params and typed returns\n lines.push(`export interface ${factoryName}Contract {`)\n lines.push(` program: string`)\n lines.push(` abi: ABI`)\n\n // read methods\n if (abi.mappings.length > 0) {\n lines.push(` read: {`)\n for (const mapping of abi.mappings) {\n const keyType = plaintextToTsType(mapping.key)\n lines.push(` ${mapping.name}: (params: { key: ${keyType} }) => Promise<unknown>`)\n }\n lines.push(` }`)\n } else {\n lines.push(` read: Record<string, (params: { key: string }) => Promise<unknown>>`)\n }\n\n // write methods — named params, returns tx ID\n if (abi.functions.length > 0) {\n lines.push(` write: {`)\n for (const fn of abi.functions) {\n const params = namedParamsType(fn, abi)\n lines.push(` ${fn.name}: (params: ${params}) => Promise<string>`)\n }\n lines.push(` }`)\n }\n\n // simulate methods — named params, typed return\n if (abi.functions.length > 0) {\n lines.push(` simulate: {`)\n for (const fn of abi.functions) {\n const params = namedParamsType(fn, abi)\n const retType = simulateReturnType(fn, abi)\n lines.push(` ${fn.name}: (params: ${params}) => Promise<${retType}>`)\n }\n lines.push(` }`)\n }\n\n // execute methods — named params, typed return + transactionId.\n // Fee belongs in proving config, not per-call params — do not add fee here.\n if (abi.functions.length > 0) {\n lines.push(` execute: {`)\n for (const fn of abi.functions) {\n const params = namedParamsType(fn, abi)\n const retType = executeReturnType(fn, abi)\n lines.push(` ${fn.name}: (params: ${params}) => Promise<${retType}>`)\n }\n lines.push(` }`)\n }\n\n lines.push(` fetchAbi: () => Promise<ABI>`)\n lines.push(`}`)\n lines.push('')\n\n // Generate factory with wrapper methods\n lines.push(`export function create${factoryName}Contract(options: {`)\n lines.push(` publicClient?: PublicClient,`)\n lines.push(` walletClient?: WalletClient,`)\n lines.push(` programSource?: string,`)\n lines.push(` imports?: Record<string, string>,`)\n lines.push(`}): ${factoryName}Contract {`)\n lines.push(` if (!options.publicClient && !options.walletClient) throw new Error('At least one of publicClient or walletClient is required')`)\n lines.push(` const client = options.publicClient && options.walletClient`)\n lines.push(` ? { public: options.publicClient, wallet: options.walletClient }`)\n lines.push(` : (options.publicClient ?? options.walletClient)!`)\n lines.push(` const raw = getContract({ program: PROGRAM_ID, abi: PROGRAM_ABI, client, programSource: options.programSource, imports: options.imports })`)\n // Proxy method access is typed as Record<string, fn> whose properties are\n // T | undefined under noUncheckedIndexedAccess. Cast to any for the internal\n // wrappers — the typed factory interface above is what consumers see.\n lines.push(` const _raw = raw as any`)\n lines.push('')\n lines.push(` return {`)\n lines.push(` program: raw.program,`)\n lines.push(` abi: raw.abi as ABI,`)\n lines.push(` read: _raw.read as ${factoryName}Contract['read'],`)\n\n // write wrappers — convert named params to positional inputs\n if (abi.functions.length > 0) {\n lines.push(` write: {`)\n for (const fn of abi.functions) {\n const names = inputNames(fn)\n const { resolveLines, resolvedNames } = resolveRecordInputs(fn)\n lines.push(` ${fn.name}: (params: any) => {`)\n if (names.length > 0) lines.push(` const { ${names.join(', ')} } = params`)\n for (const line of resolveLines) lines.push(line)\n lines.push(` return _raw.write.${fn.name}({ inputs: [${resolvedNames.join(', ')}] })`)\n lines.push(` },`)\n }\n lines.push(` },`)\n }\n\n // simulate wrappers — convert named params to positional, map outputs to typed returns\n if (abi.functions.length > 0) {\n lines.push(` simulate: {`)\n for (const fn of abi.functions) {\n const names = inputNames(fn)\n const { resolveLines, resolvedNames } = resolveRecordInputs(fn)\n lines.push(` ${fn.name}: async (params: any) => {`)\n if (names.length > 0) lines.push(` const { ${names.join(', ')} } = params`)\n for (const line of resolveLines) lines.push(line)\n\n if (fn.outputs.length === 0) {\n lines.push(` await _raw.simulate.${fn.name}({ inputs: [${resolvedNames.join(', ')}] })`)\n } else {\n lines.push(` const result = await _raw.simulate.${fn.name}({ inputs: [${resolvedNames.join(', ')}] })`)\n }\n\n if (fn.outputs.length === 0) {\n // void return\n } else if (fn.outputs.length === 1) {\n lines.push(` return ${outputMapperExpr(fn.outputs[0], 0, abi)}`)\n } else {\n const mappers = fn.outputs.map((o, i) => outputMapperExpr(o, i, abi))\n lines.push(` return [${mappers.join(', ')}] as const`)\n }\n\n lines.push(` },`)\n }\n lines.push(` },`)\n }\n\n // execute wrappers — same as simulate but includes transactionId\n if (abi.functions.length > 0) {\n lines.push(` execute: {`)\n for (const fn of abi.functions) {\n const names = inputNames(fn)\n const { resolveLines, resolvedNames } = resolveRecordInputs(fn)\n lines.push(` ${fn.name}: async (params: any) => {`)\n if (names.length > 0) lines.push(` const { ${names.join(', ')} } = params`)\n for (const line of resolveLines) lines.push(line)\n lines.push(` const result = await _raw.execute.${fn.name}({ inputs: [${resolvedNames.join(', ')}] })`)\n\n if (fn.outputs.length === 0) {\n lines.push(` return { transactionId: result.transactionId }`)\n } else if (fn.outputs.length === 1) {\n lines.push(` return { transactionId: result.transactionId, result: ${outputMapperExpr(fn.outputs[0], 0, abi)} }`)\n } else {\n const mappers = fn.outputs.map((o, i) => outputMapperExpr(o, i, abi))\n lines.push(` return { transactionId: result.transactionId, result: [${mappers.join(', ')}] as const }`)\n }\n\n lines.push(` },`)\n }\n lines.push(` },`)\n }\n\n lines.push(` fetchAbi: _raw.fetchAbi as unknown as ${factoryName}Contract['fetchAbi'],`)\n lines.push(` }`)\n lines.push(`}`)\n\n return lines\n}\n\n// ── Utility ───────────────────────────────────────────────────────────\n\nfunction recordName(record: RecordDef): string {\n return record.path[record.path.length - 1] ?? 'UnknownRecord'\n}\n\nfunction pascalCase(s: string): string {\n return s\n .split('_')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('')\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
generate
|
|
4
|
+
} from "./chunk-OU67QL3U.js";
|
|
5
|
+
|
|
6
|
+
// src/cli.ts
|
|
7
|
+
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
8
|
+
import { dirname, resolve } from "path";
|
|
9
|
+
import { parseAbi } from "@provablehq/veil-core";
|
|
10
|
+
function main() {
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
if (args.includes("--help") || args.includes("-h") || args.length === 0) {
|
|
13
|
+
console.log(`
|
|
14
|
+
Usage:
|
|
15
|
+
veil-codegen --abi <path> --out <path> Generate from a single ABI
|
|
16
|
+
veil-codegen --config <path> Generate from a config file
|
|
17
|
+
|
|
18
|
+
Options:
|
|
19
|
+
--abi <path> Path to abi.json file
|
|
20
|
+
--out <path> Output .ts file path
|
|
21
|
+
--config <path> Path to config JSON (default: veil.config.json)
|
|
22
|
+
--core-import Import path for @provablehq/veil-core (default: '@provablehq/veil-core')
|
|
23
|
+
--help, -h Show this help
|
|
24
|
+
|
|
25
|
+
Config file format (veil.config.json):
|
|
26
|
+
{
|
|
27
|
+
"programs": [
|
|
28
|
+
{ "abi": "./loyalty_token/build/abi.json", "out": "./src/generated/loyalty_token.ts" }
|
|
29
|
+
],
|
|
30
|
+
"coreImport": "@provablehq/veil-core"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Each program may set "programId" to stamp a PROGRAM_ID that differs from the
|
|
34
|
+
ABI's own program (for bindings shaped from one deployment but targeting
|
|
35
|
+
another).
|
|
36
|
+
`);
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
const configIndex = args.indexOf("--config");
|
|
40
|
+
const abiIndex = args.indexOf("--abi");
|
|
41
|
+
const outIndex = args.indexOf("--out");
|
|
42
|
+
const coreImportIndex = args.indexOf("--core-import");
|
|
43
|
+
const coreImport = coreImportIndex !== -1 ? args[coreImportIndex + 1] : void 0;
|
|
44
|
+
if (configIndex !== -1) {
|
|
45
|
+
const configPath = resolve(args[configIndex + 1] ?? "veil.config.json");
|
|
46
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
47
|
+
const resolvedCoreImport = coreImport ?? config.coreImport;
|
|
48
|
+
for (const program of config.programs) {
|
|
49
|
+
const abiPath = resolve(dirname(configPath), program.abi);
|
|
50
|
+
const outPath = resolve(dirname(configPath), program.out);
|
|
51
|
+
generateOne(abiPath, outPath, resolvedCoreImport, program.programId);
|
|
52
|
+
}
|
|
53
|
+
} else if (abiIndex !== -1 && outIndex !== -1) {
|
|
54
|
+
const abiPath = resolve(args[abiIndex + 1]);
|
|
55
|
+
const outPath = resolve(args[outIndex + 1]);
|
|
56
|
+
generateOne(abiPath, outPath, coreImport);
|
|
57
|
+
} else {
|
|
58
|
+
console.error("Error: provide either --abi + --out or --config");
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function generateOne(abiPath, outPath, coreImport, programId) {
|
|
63
|
+
const raw = JSON.parse(readFileSync(abiPath, "utf-8"));
|
|
64
|
+
const abi = parseAbi(raw);
|
|
65
|
+
const source = generate({ abi, coreImport, programId });
|
|
66
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
67
|
+
writeFileSync(outPath, source, "utf-8");
|
|
68
|
+
console.log(`Generated ${outPath} from ${abi.program}${programId ? ` (as ${programId})` : ""}`);
|
|
69
|
+
}
|
|
70
|
+
main();
|
|
71
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n// CLI entry point for @provablehq/veil-codegen.\n//\n// Usage:\n// veil-codegen --abi loyalty_token/build/abi.json --out src/generated/loyalty_token.ts\n// veil-codegen --config veil.config.json\n\nimport { readFileSync, writeFileSync, mkdirSync } from 'fs'\nimport { dirname, resolve } from 'path'\nimport { parseAbi } from '@provablehq/veil-core'\nimport { generate } from './generate.js'\n\ninterface ProgramConfig {\n abi: string\n out: string\n /**\n * Program id to stamp into the emitted PROGRAM_ID. Defaults to the ABI's own\n * `program`. Set this when the bindings' shape comes from one deployment's\n * ABI but they target another (identical-shape) deployment.\n */\n programId?: string\n}\n\ninterface Config {\n programs: ProgramConfig[]\n coreImport?: string\n}\n\nfunction main() {\n const args = process.argv.slice(2)\n\n if (args.includes('--help') || args.includes('-h') || args.length === 0) {\n console.log(`\nUsage:\n veil-codegen --abi <path> --out <path> Generate from a single ABI\n veil-codegen --config <path> Generate from a config file\n\nOptions:\n --abi <path> Path to abi.json file\n --out <path> Output .ts file path\n --config <path> Path to config JSON (default: veil.config.json)\n --core-import Import path for @provablehq/veil-core (default: '@provablehq/veil-core')\n --help, -h Show this help\n\nConfig file format (veil.config.json):\n {\n \"programs\": [\n { \"abi\": \"./loyalty_token/build/abi.json\", \"out\": \"./src/generated/loyalty_token.ts\" }\n ],\n \"coreImport\": \"@provablehq/veil-core\"\n }\n\n Each program may set \"programId\" to stamp a PROGRAM_ID that differs from the\n ABI's own program (for bindings shaped from one deployment but targeting\n another).\n`)\n process.exit(0)\n }\n\n const configIndex = args.indexOf('--config')\n const abiIndex = args.indexOf('--abi')\n const outIndex = args.indexOf('--out')\n const coreImportIndex = args.indexOf('--core-import')\n\n const coreImport = coreImportIndex !== -1 ? args[coreImportIndex + 1] : undefined\n\n if (configIndex !== -1) {\n // Config mode\n const configPath = resolve(args[configIndex + 1] ?? 'veil.config.json')\n const config: Config = JSON.parse(readFileSync(configPath, 'utf-8'))\n const resolvedCoreImport = coreImport ?? config.coreImport\n\n for (const program of config.programs) {\n const abiPath = resolve(dirname(configPath), program.abi)\n const outPath = resolve(dirname(configPath), program.out)\n generateOne(abiPath, outPath, resolvedCoreImport, program.programId)\n }\n } else if (abiIndex !== -1 && outIndex !== -1) {\n // Single file mode\n const abiPath = resolve(args[abiIndex + 1]!)\n const outPath = resolve(args[outIndex + 1]!)\n generateOne(abiPath, outPath, coreImport)\n } else {\n console.error('Error: provide either --abi + --out or --config')\n process.exit(1)\n }\n}\n\nfunction generateOne(abiPath: string, outPath: string, coreImport?: string, programId?: string) {\n const raw = JSON.parse(readFileSync(abiPath, 'utf-8'))\n const abi = parseAbi(raw)\n\n const source = generate({ abi, coreImport, programId })\n\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, source, 'utf-8')\n\n console.log(`Generated ${outPath} from ${abi.program}${programId ? ` (as ${programId})` : ''}`)\n}\n\nmain()\n"],"mappings":";;;;;;AAQA,SAAS,cAAc,eAAe,iBAAiB;AACvD,SAAS,SAAS,eAAe;AACjC,SAAS,gBAAgB;AAmBzB,SAAS,OAAO;AACd,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AAEjC,MAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,WAAW,GAAG;AACvE,YAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAuBf;AACG,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,cAAc,KAAK,QAAQ,UAAU;AAC3C,QAAM,WAAW,KAAK,QAAQ,OAAO;AACrC,QAAM,WAAW,KAAK,QAAQ,OAAO;AACrC,QAAM,kBAAkB,KAAK,QAAQ,eAAe;AAEpD,QAAM,aAAa,oBAAoB,KAAK,KAAK,kBAAkB,CAAC,IAAI;AAExE,MAAI,gBAAgB,IAAI;AAEtB,UAAM,aAAa,QAAQ,KAAK,cAAc,CAAC,KAAK,kBAAkB;AACtE,UAAM,SAAiB,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AACnE,UAAM,qBAAqB,cAAc,OAAO;AAEhD,eAAW,WAAW,OAAO,UAAU;AACrC,YAAM,UAAU,QAAQ,QAAQ,UAAU,GAAG,QAAQ,GAAG;AACxD,YAAM,UAAU,QAAQ,QAAQ,UAAU,GAAG,QAAQ,GAAG;AACxD,kBAAY,SAAS,SAAS,oBAAoB,QAAQ,SAAS;AAAA,IACrE;AAAA,EACF,WAAW,aAAa,MAAM,aAAa,IAAI;AAE7C,UAAM,UAAU,QAAQ,KAAK,WAAW,CAAC,CAAE;AAC3C,UAAM,UAAU,QAAQ,KAAK,WAAW,CAAC,CAAE;AAC3C,gBAAY,SAAS,SAAS,UAAU;AAAA,EAC1C,OAAO;AACL,YAAQ,MAAM,iDAAiD;AAC/D,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,SAAS,YAAY,SAAiB,SAAiB,YAAqB,WAAoB;AAC9F,QAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AACrD,QAAM,MAAM,SAAS,GAAG;AAExB,QAAM,SAAS,SAAS,EAAE,KAAK,YAAY,UAAU,CAAC;AAEtD,YAAU,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/C,gBAAc,SAAS,QAAQ,OAAO;AAEtC,UAAQ,IAAI,aAAa,OAAO,SAAS,IAAI,OAAO,GAAG,YAAY,QAAQ,SAAS,MAAM,EAAE,EAAE;AAChG;AAEA,KAAK;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ABI } from '@provablehq/veil-core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Options for {@link generate}.
|
|
5
|
+
*
|
|
6
|
+
* @property abi Parsed ABI the bindings are generated from — it supplies the
|
|
7
|
+
* structs, records, functions, mappings, and storage variables to emit.
|
|
8
|
+
* @property coreImport Import path emitted for `@provablehq/veil-core` types. Defaults to
|
|
9
|
+
* `'@provablehq/veil-core'`. Override when the generated file resolves core through an
|
|
10
|
+
* alias or a relative path (e.g. inside the monorepo).
|
|
11
|
+
* @property programId Program id to stamp into the emitted `PROGRAM_ID` and
|
|
12
|
+
* the generated contract factory. Defaults to the ABI's own `program`.
|
|
13
|
+
* Override when the bindings' shape is taken from one deployment's ABI but
|
|
14
|
+
* they target another — e.g. when a newer program version's ABI is the only
|
|
15
|
+
* one current tooling can parse, yet the live deployment (identical shape)
|
|
16
|
+
* has a different id.
|
|
17
|
+
*/
|
|
18
|
+
interface GenerateOptions {
|
|
19
|
+
abi: ABI;
|
|
20
|
+
coreImport?: string;
|
|
21
|
+
programId?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generates TypeScript source code from an Aleo program ABI.
|
|
25
|
+
*
|
|
26
|
+
* Produces:
|
|
27
|
+
* - Struct interfaces
|
|
28
|
+
* - Record interfaces with correctly typed fields
|
|
29
|
+
* - Record mapper functions (RecordValue → typed interface)
|
|
30
|
+
* - Function input and output types
|
|
31
|
+
* - Mapping key/value types
|
|
32
|
+
* - Storage variable types
|
|
33
|
+
*/
|
|
34
|
+
declare function generate(options: GenerateOptions): string;
|
|
35
|
+
|
|
36
|
+
export { type GenerateOptions, generate };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@provablehq/veil-codegen",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Generates executable TypeScript contracts from Aleo program ABIs.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/ProvableHQ/veil.git",
|
|
9
|
+
"directory": "packages/codegen"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/ProvableHQ/veil#readme",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"bin": {
|
|
14
|
+
"veil-codegen": "./dist/cli.js"
|
|
15
|
+
},
|
|
16
|
+
"main": "dist/index.js",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@provablehq/veil-core": "0.4.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"tsup": "^8.0.0",
|
|
39
|
+
"typescript": "^5.7.0",
|
|
40
|
+
"@provablehq/veil-aleo-devnode": "0.4.0",
|
|
41
|
+
"@provablehq/veil-leo": "0.4.0",
|
|
42
|
+
"@provablehq/veil-aleo-sdk": "0.4.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"test": "vitest run"
|
|
47
|
+
}
|
|
48
|
+
}
|