@better-sol/cli 0.1.0-alpha.1 → 0.1.0-alpha.5

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
@@ -1,5 +1,9 @@
1
1
  # @better-sol/cli
2
2
 
3
+ > **Alpha**
4
+ >
5
+ > Better Sol is in early development. APIs may change, rough edges exist, and things can break. Your feedback shapes what comes next. Thank you for being an early adopter.
6
+
3
7
  The Better Sol command-line tool. Scaffold programs, compile and deploy to Solana, generate database schemas, and import external programs.
4
8
 
5
9
  No installation needed. Run with `npx` or `bunx`.
@@ -11,7 +15,7 @@ No installation needed. Run with `npx` or `bunx`.
11
15
  Set up a new project.
12
16
 
13
17
  ```bash
14
- npx @better-sol/cli init
18
+ npx @better-sol/cli@alpha init
15
19
  ```
16
20
 
17
21
  Creates a payer keypair at `keypair.json`, a `programs/` directory, and a `.gitignore`. Detects your existing Solana CLI keypair at `~/.config/solana/id.json` if you have one. Offers to install `better-sol` if a `package.json` exists.
@@ -26,7 +30,7 @@ Creates a payer keypair at `keypair.json`, a `programs/` directory, and a `.giti
26
30
  Scaffold a new program.
27
31
 
28
32
  ```bash
29
- npx @better-sol/cli create counter
33
+ npx @better-sol/cli@alpha create counter
30
34
  ```
31
35
 
32
36
  Generates `programs/counter.ts` with a working counter template and `.better-sol/counter.json` with the program keypair.
@@ -41,7 +45,7 @@ Generates `programs/counter.ts` with a working counter template and `.better-sol
41
45
  Compile and deploy to Solana.
42
46
 
43
47
  ```bash
44
- npx @better-sol/cli deploy
48
+ npx @better-sol/cli@alpha deploy
45
49
  ```
46
50
 
47
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.
@@ -62,10 +66,10 @@ Import an external program from an on-chain address or a local IDL file.
62
66
 
63
67
  ```bash
64
68
  # From an on-chain program
65
- npx @better-sol/cli generate idl 12b3t1cNiAUoYLiWFEnFa4w6qYxVAiqCWU7KZuzLPYtH
69
+ npx @better-sol/cli@alpha generate idl 12b3t1cNiAUoYLiWFEnFa4w6qYxVAiqCWU7KZuzLPYtH
66
70
 
67
71
  # From a local IDL JSON file
68
- npx @better-sol/cli generate idl ./staking-idl.json
72
+ npx @better-sol/cli@alpha generate idl ./staking-idl.json
69
73
  ```
70
74
 
71
75
  Produces a typed `.ts` file in `generated/`. Detects whether the argument is an address or a file path automatically.
@@ -81,7 +85,7 @@ Produces a typed `.ts` file in `generated/`. Detects whether the argument is an
81
85
  Generate a Drizzle ORM schema from your account definitions.
82
86
 
83
87
  ```bash
84
- npx @better-sol/cli generate db
88
+ npx @better-sol/cli@alpha generate db
85
89
  ```
86
90
 
87
91
  | Flag | Default | Description |
@@ -95,7 +99,7 @@ npx @better-sol/cli generate db
95
99
  Save your compiler API key.
96
100
 
97
101
  ```bash
98
- npx @better-sol/cli login
102
+ npx @better-sol/cli@alpha login
99
103
  ```
100
104
 
101
105
  Saves your key to `.better-sol/auth.json`. Without a key you get 5 compiles per hour. With a key, 100 per hour.
@@ -105,7 +109,7 @@ Saves your key to `.better-sol/auth.json`. Without a key you get 5 compiles per
105
109
  Submit a deployed program for OtterSec verified-builds.
106
110
 
107
111
  ```bash
108
- npx @better-sol/cli verify counter --program-id <address>
112
+ npx @better-sol/cli@alpha verify counter --program-id <address>
109
113
  ```
110
114
 
111
115
  | Flag | Description |
package/dist/index.js CHANGED
@@ -2,13 +2,13 @@
2
2
  import { createRequire } from "node:module";
3
3
  import { cancel, confirm, intro, isCancel, log, outro, select, spinner, text } from "@clack/prompts";
4
4
  import { Command } from "commander";
5
- import { fileURLToPath, pathToFileURL } from "node:url";
6
5
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
7
6
  import path, { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
8
7
  import { homedir } from "node:os";
9
8
  import { execSync } from "node:child_process";
10
9
  import { generateKeyPairSigner, getAddressDecoder } from "@solana/kit";
11
10
  import { access, mkdir, opendir, readFile, writeFile } from "node:fs/promises";
11
+ import { fileURLToPath, pathToFileURL } from "node:url";
12
12
  import { parseSync } from "oxc-parser";
13
13
  import { AnchorProvider, Program } from "@coral-xyz/anchor";
14
14
  import crypto$1 from "crypto";
@@ -3036,11 +3036,18 @@ function primitiveLayout(type) {
3036
3036
  //#endregion
3037
3037
  //#region src/parser/discover.ts
3038
3038
  function globToRegex(pattern) {
3039
- const regexParts = pattern.split("/").map((part) => {
3040
- if (part === "**") return ".*";
3041
- return part.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
3042
- });
3043
- return new RegExp(`^${regexParts.join("/")}$`);
3039
+ const parts = pattern.split("/");
3040
+ const regexParts = [];
3041
+ for (let i = 0; i < parts.length; i++) {
3042
+ const part = parts[i];
3043
+ const isLast = i === parts.length - 1;
3044
+ if (part === "**") regexParts.push("(.*\\/)?");
3045
+ else {
3046
+ regexParts.push(part.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]"));
3047
+ if (!isLast) regexParts.push("/");
3048
+ }
3049
+ }
3050
+ return new RegExp(`^${regexParts.join("")}$`);
3044
3051
  }
3045
3052
  async function findFiles(pattern) {
3046
3053
  const regex = globToRegex(pattern);
@@ -3098,6 +3105,7 @@ async function discoverProgramsWithSpinner(src) {
3098
3105
  //#region src/commands/deploy.ts
3099
3106
  const DEFAULT_PAYER_PATH = "keypair.json";
3100
3107
  const AIRDROP_LAMPORTS = 2000000000n;
3108
+ const AIRDROP_RETRIES = 3;
3101
3109
  const MIN_DEPLOY_BALANCE = 1500000000n;
3102
3110
  async function deploy(options) {
3103
3111
  intro("better-sol deploy");
@@ -3208,14 +3216,19 @@ async function ensureFunded(address, cluster, rpcUrl) {
3208
3216
  return;
3209
3217
  }
3210
3218
  s.message(`Low balance (${(Number(balance) / 1e9).toFixed(4)} SOL). Requesting airdrop on ${cluster}...`);
3211
- try {
3219
+ for (let attempt = 1; attempt <= AIRDROP_RETRIES; attempt++) try {
3212
3220
  await confirmSignature(await requestAirdrop(address, rpcUrl, AIRDROP_LAMPORTS), rpcUrl);
3213
3221
  const newBalance = await getBalance(address, rpcUrl);
3214
3222
  s.stop(`Funded. Balance: ${(Number(newBalance) / 1e9).toFixed(2)} SOL`);
3223
+ return;
3215
3224
  } catch {
3216
- s.stop("Airdrop failed");
3217
- throw new Error(`Failed to airdrop SOL on ${cluster}. Fund ${address} manually or try again.`);
3225
+ if (attempt < AIRDROP_RETRIES) {
3226
+ s.message(`Airdrop attempt ${attempt} failed, retrying...`);
3227
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
3228
+ }
3218
3229
  }
3230
+ s.stop("Airdrop failed");
3231
+ throw new Error(`Failed to airdrop SOL on ${cluster}. Fund ${address} manually or try again.`);
3219
3232
  }
3220
3233
  function printProgramSummary(program, cluster, out, wroteRust) {
3221
3234
  log.info(`Program: ${program.name}`);
@@ -69246,7 +69259,7 @@ async function gitCommit() {
69246
69259
  //#endregion
69247
69260
  //#region src/index.ts
69248
69261
  const cli = new Command();
69249
- cli.name("better-sol").description("TypeScript-first Solana program tooling — run with npx @better-sol/cli").version("0.1.0-alpha.1");
69262
+ cli.name("better-sol").description("TypeScript-first Solana program tooling — run with npx @better-sol/cli").version("0.1.0-alpha.5");
69250
69263
  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)));
69251
69264
  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)));
69252
69265
  cli.command("login").description("Save your compiler API key").action(() => run(() => login()));
@@ -69255,7 +69268,7 @@ const generate = cli.command("generate").description("Generate derived artifacts
69255
69268
  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)));
69256
69269
  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)));
69257
69270
  cli.command("verify").description("Submit a deployed program for OtterSec verified-builds").argument("[program]", "program name or program ID").option("--program-id <programId>", "program ID to verify").option("--lib-name <name>", "Rust library name (defaults to program name)").option("--mount-path <path>", "subdirectory in repo where Cargo.toml lives (defaults to generated/<name>)").action((program, options) => run(() => verify(program, options)));
69258
- if (process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === process.argv[1]) cli.parse(process.argv);
69271
+ cli.parse(process.argv);
69259
69272
  async function run(task) {
69260
69273
  try {
69261
69274
  await task();