@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 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, generates Anchor Rust, compiles it via the cloud API, and deploys the binary. On devnet and testnet, automatically funds your payer if the balance is low.
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` | Generate Rust without compiling or deploying |
60
- | `--verify` | `false` | Write Rust for verified builds |
61
- | `--output <dir>` | `generated` | Output directory for Rust files |
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/**/*.so",
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
- for (const project of projects) printProgramSummary(project.program, cluster, outDir, true);
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"} with Better Sol compiler`);
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 ${out}/ directory to a public repository`);
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
- async function removeGeneratedSoFile(outDir, programName) {
3233
- await rm(join(outDir, programName, "target", "deploy", `${programName}.so`), { force: true });
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.10");
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("Generate Rust, 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>", "generated Rust output directory").action((options) => run(() => deploy(options)));
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)));