@better-sol/cli 0.1.0-alpha.10 → 0.1.0-alpha.11
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 +4 -4
- package/dist/index.js +24 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ Compile and deploy to Solana.
|
|
|
48
48
|
npx @better-sol/cli@alpha deploy
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
Parses your TypeScript,
|
|
51
|
+
Parses your TypeScript, compiles it via the cloud API, and deploys the binary. On devnet and testnet, automatically funds your payer if the balance is low. Compiled binaries are cached locally in `.better-sol/cache/` for testing.
|
|
52
52
|
|
|
53
53
|
| Flag | Default | Description |
|
|
54
54
|
|---|---|---|
|
|
@@ -56,9 +56,9 @@ Parses your TypeScript, generates Anchor Rust, compiles it via the cloud API, an
|
|
|
56
56
|
| `--program <name>` | all programs | Target a specific program |
|
|
57
57
|
| `--payer <path>` | `keypair.json` | Payer keypair path |
|
|
58
58
|
| `--cluster <cluster>` | `devnet` | `devnet`, `testnet`, `mainnet`, `localnet` |
|
|
59
|
-
| `--dry-run` | `false` |
|
|
60
|
-
| `--verify` | `false` | Write Rust for verified builds |
|
|
61
|
-
| `--output <dir>` | `generated` |
|
|
59
|
+
| `--dry-run` | `false` | Validate without compiling or deploying |
|
|
60
|
+
| `--verify` | `false` | Write Rust for OtterSec verified builds |
|
|
61
|
+
| `--output <dir>` | `generated` | Rust output directory (only used with `--verify`) |
|
|
62
62
|
|
|
63
63
|
### `generate idl`
|
|
64
64
|
|
package/dist/index.js
CHANGED
|
@@ -933,7 +933,7 @@ async function discoverProgramsWithSpinner(src) {
|
|
|
933
933
|
const PAYER_KEYPAIR_PATH = "keypair.json";
|
|
934
934
|
const GITIGNORE_ENTRIES = [
|
|
935
935
|
".better-sol/",
|
|
936
|
-
"generated
|
|
936
|
+
"generated/",
|
|
937
937
|
"keypair.json",
|
|
938
938
|
"node_modules/"
|
|
939
939
|
];
|
|
@@ -3134,21 +3134,18 @@ const DEFAULT_PAYER_PATH = "keypair.json";
|
|
|
3134
3134
|
const AIRDROP_LAMPORTS = 2000000000n;
|
|
3135
3135
|
const AIRDROP_RETRIES = 3;
|
|
3136
3136
|
const MIN_DEPLOY_BALANCE = 1500000000n;
|
|
3137
|
+
const CACHE_DIR = `${BETTER_SOL_DIR}/cache`;
|
|
3137
3138
|
async function deploy(options) {
|
|
3138
3139
|
intro("better-sol deploy");
|
|
3139
3140
|
const apiKey = await getStoredApiKey();
|
|
3140
3141
|
const config = await loadConfig();
|
|
3141
3142
|
const cluster = parseCluster(options.cluster, config.cluster);
|
|
3142
3143
|
const src = options.src ?? config.programs;
|
|
3143
|
-
const out = options.output ?? config.out;
|
|
3144
|
-
const outDir = cwdPath(out);
|
|
3145
3144
|
const payerPath = resolvePayerPath(options.payer, config.payer);
|
|
3146
3145
|
const payer = await readKeypair(payerPath);
|
|
3147
3146
|
const rpcUrl = clusterUrl(cluster);
|
|
3148
|
-
const writesRust = options.verify || options.dryRun || options.output !== void 0;
|
|
3149
3147
|
log.step(`Cluster: ${cluster}`);
|
|
3150
3148
|
log.step(`Source: ${src}`);
|
|
3151
|
-
if (writesRust) log.step(`Output: ${out}`);
|
|
3152
3149
|
await ensureFunded(payer.publicKey, cluster, rpcUrl);
|
|
3153
3150
|
const programs = await discoverProgramsWithSpinner(src);
|
|
3154
3151
|
const matched = options.program !== void 0 ? programs.filter((p) => p.name === options.program) : programs;
|
|
@@ -3157,26 +3154,12 @@ async function deploy(options) {
|
|
|
3157
3154
|
throw new Error(`No program named '${options.program}' found in ${src}.\nAvailable programs:\n${available}`);
|
|
3158
3155
|
}
|
|
3159
3156
|
const projects = matched.map((program) => generateAnchorProject(program));
|
|
3160
|
-
await Promise.all(projects.map((project) => removeGeneratedSoFile(outDir, project.program.name)));
|
|
3161
|
-
if (writesRust) {
|
|
3162
|
-
const writeSpinner = spinner();
|
|
3163
|
-
writeSpinner.start("Writing generated Anchor projects");
|
|
3164
|
-
await ensureDirectory(outDir);
|
|
3165
|
-
await Promise.all(projects.map(async (project) => {
|
|
3166
|
-
const dir = join(outDir, project.program.name);
|
|
3167
|
-
await ensureDirectory(join(dir, "src"));
|
|
3168
|
-
writeFileSync(join(dir, "Cargo.toml"), project.cargoToml);
|
|
3169
|
-
writeFileSync(join(dir, "src", "lib.rs"), project.libRs);
|
|
3170
|
-
}));
|
|
3171
|
-
writeSpinner.stop("Generated Anchor projects written");
|
|
3172
|
-
}
|
|
3173
3157
|
if (options.dryRun) {
|
|
3174
|
-
|
|
3175
|
-
outro(`Dry run complete — Rust written to ${out}/. No compilation or deployment performed.`);
|
|
3158
|
+
outro("Dry run complete. No compilation or deployment performed.");
|
|
3176
3159
|
return;
|
|
3177
3160
|
}
|
|
3178
3161
|
const compileSpinner = spinner();
|
|
3179
|
-
compileSpinner.start(`Compiling ${matched.length === 1 ? matched[0]?.name : matched.length + " programs"}
|
|
3162
|
+
compileSpinner.start(`Compiling ${matched.length === 1 ? matched[0]?.name : matched.length + " programs"}`);
|
|
3180
3163
|
let compileResults;
|
|
3181
3164
|
try {
|
|
3182
3165
|
compileResults = await Promise.all(projects.map((project) => compileProgram({
|
|
@@ -3201,6 +3184,8 @@ async function deploy(options) {
|
|
|
3201
3184
|
throw new Error(`Compilation failed for ${project.program.name}.${logs}`);
|
|
3202
3185
|
}
|
|
3203
3186
|
log.step(`Compiled: ${compileTime}`);
|
|
3187
|
+
if (result.bytecodeSha256) log.step(`Binary: sha256:${result.bytecodeSha256.slice(0, 16)}...`);
|
|
3188
|
+
writeBytecode(project.program.name, result.bytecode);
|
|
3204
3189
|
const programKeypairPath = cwdJoin(BETTER_SOL_DIR, `${project.program.name}.json`);
|
|
3205
3190
|
const solanaPath = ensureSolanaCli();
|
|
3206
3191
|
const deploySpinner = spinner();
|
|
@@ -3223,14 +3208,27 @@ async function deploy(options) {
|
|
|
3223
3208
|
}
|
|
3224
3209
|
}
|
|
3225
3210
|
if (options.verify) {
|
|
3211
|
+
const verifyDir = cwdPath(options.output ?? config.out);
|
|
3212
|
+
await writeRustForVerify(projects, verifyDir);
|
|
3226
3213
|
log.info("To verify this build on-chain:");
|
|
3227
|
-
log.step(`1. Commit and push the ${
|
|
3214
|
+
log.step(`1. Commit and push the ${verifyDir}/ directory to a public repository`);
|
|
3228
3215
|
log.step(`2. Run \`${CLI_COMMAND$1} verify ${matched[0]?.address ?? "<program-id>"}\``);
|
|
3229
3216
|
}
|
|
3230
3217
|
outro("Deploy complete.");
|
|
3231
3218
|
}
|
|
3232
|
-
|
|
3233
|
-
|
|
3219
|
+
function writeBytecode(programName, bytecode) {
|
|
3220
|
+
const cachePath = cwdPath(CACHE_DIR);
|
|
3221
|
+
ensureDirectory(cachePath);
|
|
3222
|
+
writeFileSync(join(cachePath, `${programName}.so`), Buffer.from(bytecode, "base64"));
|
|
3223
|
+
}
|
|
3224
|
+
async function writeRustForVerify(projects, outDir) {
|
|
3225
|
+
await ensureDirectory(outDir);
|
|
3226
|
+
await Promise.all(projects.map(async (project) => {
|
|
3227
|
+
const dir = join(outDir, project.program.name);
|
|
3228
|
+
await ensureDirectory(join(dir, "src"));
|
|
3229
|
+
writeFileSync(join(dir, "Cargo.toml"), project.cargoToml);
|
|
3230
|
+
writeFileSync(join(dir, "src", "lib.rs"), project.libRs);
|
|
3231
|
+
}));
|
|
3234
3232
|
}
|
|
3235
3233
|
async function deployCompiledProgram(params) {
|
|
3236
3234
|
const deployDir = await mkdtemp(join(tmpdir(), "better-sol-deploy-"));
|
|
@@ -3307,12 +3305,6 @@ async function ensureFunded(address, cluster, rpcUrl) {
|
|
|
3307
3305
|
s.stop("Airdrop failed");
|
|
3308
3306
|
throw new Error(`Failed to airdrop SOL on ${cluster}. Fund ${address} manually or try again.`);
|
|
3309
3307
|
}
|
|
3310
|
-
function printProgramSummary(program, cluster, out, wroteRust) {
|
|
3311
|
-
log.info(`Program: ${program.name}`);
|
|
3312
|
-
log.step(`Address: ${program.address}`);
|
|
3313
|
-
log.step(`Cluster: ${cluster}`);
|
|
3314
|
-
if (wroteRust) log.step(`Rust: ${out}/${program.name}/`);
|
|
3315
|
-
}
|
|
3316
3308
|
//#endregion
|
|
3317
3309
|
//#region src/generator/db.ts
|
|
3318
3310
|
function isDbDialect(value) {
|
|
@@ -69336,11 +69328,11 @@ async function gitCommit() {
|
|
|
69336
69328
|
//#endregion
|
|
69337
69329
|
//#region src/index.ts
|
|
69338
69330
|
const cli = new Command();
|
|
69339
|
-
cli.name("better-sol").description("Write Solana programs in TypeScript. Run with npx @better-sol/cli@alpha").version("0.1.0-alpha.
|
|
69331
|
+
cli.name("better-sol").description("Write Solana programs in TypeScript. Run with npx @better-sol/cli@alpha").version("0.1.0-alpha.11");
|
|
69340
69332
|
cli.command("init").description("Initialize a better-sol project").option("--force", "overwrite existing files", false).option("--skip-install", "skip installing dependencies", false).action((options) => run(() => init(options)));
|
|
69341
69333
|
cli.command("create").description("Create a new better-sol program").argument("[name]", "program name").option("--dir <dir>", "program directory", "programs").option("--force", "overwrite existing files", false).action((name, options) => run(() => create(name, options)));
|
|
69342
69334
|
cli.command("login").description("Save your compiler API key").argument("[apiKey]", "compiler API key").action((apiKey) => run(() => login(apiKey)));
|
|
69343
|
-
cli.command("deploy").description("
|
|
69335
|
+
cli.command("deploy").description("Compile and deploy programs").option("--src <glob>", "program source glob").option("--program <name>", "target a specific program by name").option("--payer <path>", "payer keypair path").option("--cluster <cluster>", "devnet, testnet, mainnet, or localnet").option("--verify", "write generated Rust for verified builds", false).option("--dry-run", "generate and validate without compiling or deploying", false).option("--output <dir>", "output directory for verified build Rust", "generated").action((options) => run(() => deploy(options)));
|
|
69344
69336
|
const generate = cli.command("generate").description("Generate derived artifacts");
|
|
69345
69337
|
generate.command("db").description("Generate a database schema from account definitions").option("--dialect <dialect>", "postgres, mysql, or sqlite", "postgres").option("--out <path>", "output file", "src/db/better-sol.ts").option("--src <glob>", "program source glob").action((options) => run(() => generateDb(options)));
|
|
69346
69338
|
generate.command("idl").description("Generate a typed Better Sol program from an IDL file or on-chain program address").argument("<source>", "path to IDL JSON file or on-chain program address").option("--out <path>", "output TypeScript file (default: generated/<name>.ts)").option("--name <name>", "program name override (default: derived from IDL)").option("--cluster <cluster>", "cluster for on-chain IDL fetch (mainnet, devnet, testnet, localnet)", "mainnet").action((source, options) => run(() => generateIdl(source, options)));
|