@caatinga/cli 2.0.1 → 2.1.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/README.md CHANGED
@@ -49,7 +49,7 @@ npx caatinga invoke counter.increment --network testnet --source alice
49
49
  | `caatinga doctor [--network <network>] [--source <identity>]` | Check local Node, Stellar CLI, Rust, config, artifacts, network, and source identity setup |
50
50
  | `caatinga build [contract]` | Compile contract WASM through Stellar CLI (default contract: `counter`) |
51
51
  | `caatinga deploy [contract]` | Deploy one contract or the full configured graph; record IDs in artifacts |
52
- | `caatinga generate <contract>` | Generate TypeScript bindings from a deployed contract ID |
52
+ | `caatinga generate [contract]` | Generate TypeScript bindings from a deployed contract ID; omit the name to generate for all deployed contracts |
53
53
  | `caatinga invoke <contract.method>` | Invoke a deployed contract method; extra args forward to Stellar CLI |
54
54
 
55
55
  The supported CLI flow is `init -> build -> deploy -> generate -> invoke`.
package/dist/index.js CHANGED
@@ -197,6 +197,16 @@ function registerDeployCommand(program2) {
197
197
  logger.info(` Contract ID: ${contract.contractId}`);
198
198
  }
199
199
  logger.info("Artifacts updated: caatinga.artifacts.json");
200
+ if (result.deployedContracts.length > 0) {
201
+ logger.info("");
202
+ logger.info("Next:");
203
+ for (const contract of result.deployedContracts) {
204
+ logger.info(` npx caatinga generate ${contract.name} --network ${result.network.name}`);
205
+ }
206
+ logger.info(" npm run dev");
207
+ logger.info("");
208
+ logger.info("Run generate before npm run dev so the app uses real bindings, not the stub.");
209
+ }
200
210
  }));
201
211
  }
202
212
 
@@ -441,20 +451,29 @@ function registerDoctorCommand(program2) {
441
451
  }
442
452
 
443
453
  // src/commands/generate.command.ts
444
- import { generateBindings, loadConfig as loadConfig5 } from "@caatinga/core";
454
+ import { generateBindingsGraph, loadConfig as loadConfig5 } from "@caatinga/core";
445
455
  function registerGenerateCommand(program2) {
446
- program2.command("generate").description("Generate TypeScript bindings for a deployed contract").argument("<contract>", "Contract name").option("-n, --network <network>", "Configured network name").action((contractName, options) => runCliAction(async () => {
456
+ program2.command("generate").description("Generate TypeScript bindings for deployed contracts").argument("[contract]", "Contract name (defaults to all deployed contracts)").option("-n, --network <network>", "Configured network name").action((contractName, options) => runCliAction(async () => {
447
457
  const config = await loadConfig5();
448
- const result = await generateBindings({
458
+ const { network, results } = await generateBindingsGraph({
449
459
  config,
450
460
  contractName,
451
461
  networkName: options.network
452
462
  });
453
463
  logger.success("Client generated");
454
464
  logger.info("");
455
- logger.info(`Contract: ${result.contractName}`);
456
- logger.info(`Network: ${result.network.name}`);
457
- logger.info(`Output: ${result.outputDir}`);
465
+ logger.info(`Network: ${network.name}`);
466
+ for (const result of results) {
467
+ logger.info("");
468
+ logger.info(`Contract: ${result.contractName}`);
469
+ logger.info(`Output: ${result.outputDir}`);
470
+ logger.info(`Import path: ${result.importPath}`);
471
+ if (result.legacyStubRemoved) {
472
+ logger.info(`Removed legacy stub: ${config.frontend.bindingsOutput}/${result.contractName}.ts`);
473
+ }
474
+ }
475
+ logger.info("");
476
+ logger.info("Next: import bindings from the import path above, then run npm run dev");
458
477
  }));
459
478
  }
460
479
 
@@ -534,13 +553,27 @@ function registerInitCommand(program2) {
534
553
  logger.info(`Template: ${result.template.name}@${result.template.version}`);
535
554
  logger.info(`Path: ${targetDir}`);
536
555
  logger.info("");
556
+ const defaultContract = result.template.contracts.default;
537
557
  logger.info("Next steps:");
538
558
  logger.info(` cd ${projectDirectory}`);
539
559
  logger.info(" npm install");
540
- const defaultContract = result.template.contracts.default;
560
+ if (defaultContract) {
561
+ logger.info(` npx caatinga build ${defaultContract}`);
562
+ logger.info(
563
+ ` npx caatinga deploy ${defaultContract} --network testnet --source <identity>`
564
+ );
565
+ logger.info(` npx caatinga generate ${defaultContract} --network testnet`);
566
+ } else {
567
+ logger.info(" npx caatinga build");
568
+ logger.info(" npx caatinga deploy --network testnet --source <identity>");
569
+ logger.info(" npx caatinga generate --network testnet");
570
+ }
571
+ logger.info(" npm run dev");
572
+ logger.info("");
541
573
  logger.info(
542
- defaultContract ? ` npx caatinga build ${defaultContract}` : " npx caatinga build"
574
+ "Note: deploy and generate the contract before interacting in the frontend \u2014"
543
575
  );
576
+ logger.info("the dApp reads the contract ID from caatinga.artifacts.json.");
544
577
  }));
545
578
  }
546
579
 
@@ -569,7 +602,7 @@ function registerInvokeCommand(program2) {
569
602
  }
570
603
 
571
604
  // src/version.ts
572
- var CAATINGA_CLI_VERSION = "2.0.1";
605
+ var CAATINGA_CLI_VERSION = "2.1.0";
573
606
 
574
607
  // src/program.ts
575
608
  function createProgram() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caatinga/cli",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Caatinga CLI for building dApps on Stellar/Soroban",
5
5
  "keywords": [
6
6
  "stellar",
@@ -43,7 +43,7 @@
43
43
  "LICENSE"
44
44
  ],
45
45
  "dependencies": {
46
- "@caatinga/core": "^2.0.1",
46
+ "@caatinga/core": "^2.1.0",
47
47
  "chalk": "^5.4.1",
48
48
  "commander": "^12.1.0"
49
49
  },
@@ -3,7 +3,7 @@
3
3
  "version": "0.1.0",
4
4
  "description": "Experimental multi-contract Soroban template with token dependency injection.",
5
5
  "caatinga": {
6
- "compatibleCore": "^2.0.1",
6
+ "compatibleCore": "^2.1.0",
7
7
  "templateVersion": 1
8
8
  },
9
9
  "frontend": {
@@ -12,15 +12,15 @@
12
12
  "caatinga:generate": "caatinga generate token && caatinga generate marketplace"
13
13
  },
14
14
  "dependencies": {
15
- "@caatinga/client": "^2.0.1",
16
- "@caatinga/core": "^2.0.1",
15
+ "@caatinga/client": "^2.1.0",
16
+ "@caatinga/core": "^2.1.0",
17
17
  "@vitejs/plugin-react": "^4.3.4",
18
18
  "react": "^18.3.1",
19
19
  "react-dom": "^18.3.1",
20
20
  "vite": "^6.0.6"
21
21
  },
22
22
  "devDependencies": {
23
- "@caatinga/cli": "^2.0.1",
23
+ "@caatinga/cli": "^2.1.0",
24
24
  "@types/react": "^18.3.18",
25
25
  "@types/react-dom": "^18.3.5",
26
26
  "typescript": "^5.7.2"
@@ -15,6 +15,8 @@ npm run dev # or: pnpm dev
15
15
 
16
16
  Run `build` before `deploy` (WASM required) and `deploy` before `generate` (contract ID required).
17
17
 
18
+ The checked-in binding stub under `src/contracts/generated/counter/src/index.ts` is a placeholder so the template type-checks before you run `caatinga generate`. Run `caatinga generate` before `npm run dev` so the browser uses real Stellar CLI bindings instead of the stub.
19
+
18
20
  Use a local Stellar CLI identity alias for `--source`; public `G...` addresses, seed phrases, and secret keys are rejected for signing operations.
19
21
 
20
22
  ## Package managers
@@ -38,7 +40,7 @@ After `caatinga generate`, wire generated bindings to the client:
38
40
  ```ts
39
41
  import { createCaatingaClient } from "@caatinga/client";
40
42
  import { createStellarWalletsKitAdapter } from "@caatinga/client/stellar-wallets-kit";
41
- import * as Counter from "./contracts/generated/counter";
43
+ import * as Counter from "./contracts/generated/counter/src/index.js";
42
44
  import artifacts from "../caatinga.artifacts.json";
43
45
 
44
46
  const wallet = createStellarWalletsKitAdapter();
@@ -3,7 +3,7 @@
3
3
  "version": "0.1.0",
4
4
  "description": "Minimal Vite + React + Soroban counter dApp.",
5
5
  "caatinga": {
6
- "compatibleCore": "^2.0.1",
6
+ "compatibleCore": "^2.1.0",
7
7
  "templateVersion": 1
8
8
  },
9
9
  "frontend": {
@@ -12,16 +12,18 @@
12
12
  "caatinga:generate": "caatinga generate counter"
13
13
  },
14
14
  "dependencies": {
15
- "@caatinga/client": "^2.0.1",
16
- "@caatinga/core": "^2.0.1",
15
+ "@caatinga/client": "^2.1.0",
16
+ "@caatinga/core": "^2.1.0",
17
17
  "@creit.tech/stellar-wallets-kit": "^1.9.5",
18
+ "@stellar/stellar-sdk": "^14.5.0",
19
+ "buffer": "^6.0.3",
18
20
  "@vitejs/plugin-react": "^4.3.4",
19
21
  "react": "^18.3.1",
20
22
  "react-dom": "^18.3.1",
21
23
  "vite": "^6.0.6"
22
24
  },
23
25
  "devDependencies": {
24
- "@caatinga/cli": "^2.0.1",
26
+ "@caatinga/cli": "^2.1.0",
25
27
  "@types/react": "^18.3.18",
26
28
  "@types/react-dom": "^18.3.5",
27
29
  "typescript": "^5.7.2"
@@ -1,7 +1,7 @@
1
1
  import { createCaatingaClient } from "@caatinga/client";
2
2
  import type { CaatingaArtifacts } from "@caatinga/core/browser";
3
3
  import artifactsJson from "../caatinga.artifacts.json";
4
- import * as Counter from "./contracts/generated/counter.js";
4
+ import * as Counter from "./contracts/generated/counter/src/index.js";
5
5
  import { stellarWalletAdapter } from "./wallet.js";
6
6
 
7
7
  const artifacts = artifactsJson as CaatingaArtifacts;
@@ -1,17 +1,9 @@
1
1
  import { useCallback, useEffect, useMemo, useState } from "react";
2
2
  import { caatingaClient } from "../caatinga.js";
3
- import { CaatingaError } from "@caatinga/core/browser";
3
+ import { formatCaatingaError } from "@caatinga/core/browser";
4
4
  import { useWallet } from "../context/WalletContext.js";
5
5
  import { LoadingModal } from "./LoadingModal.js";
6
6
 
7
- function formatCaatingaError(error: unknown): string {
8
- if (error instanceof CaatingaError) {
9
- return `[${error.code}] ${error.message}\n\n${error.hint}`;
10
- }
11
-
12
- return error instanceof Error ? error.message : String(error);
13
- }
14
-
15
7
  export function CounterCard() {
16
8
  const { publicKey } = useWallet();
17
9
  const [count, setCount] = useState<number | null>(null);
@@ -0,0 +1,43 @@
1
+ // Placeholder bindings. This file exists so the template type-checks before you
2
+ // run `caatinga generate`. It does NOT talk to the chain — every method throws a
3
+ // clear, actionable error. `caatinga generate counter` overwrites this file with
4
+ // real Stellar CLI bindings.
5
+ import { CaatingaError, CaatingaErrorCode } from "@caatinga/core/browser";
6
+
7
+ // Marker the client checks to detect that real bindings haven't been generated
8
+ // yet. Real Stellar CLI bindings never export this.
9
+ export const __caatingaPlaceholder = true;
10
+
11
+ const GENERATE_HINT =
12
+ "Run `npx caatinga generate counter --network testnet`, then restart the dev server.";
13
+
14
+ function placeholderBinding(method: string): never {
15
+ throw new CaatingaError(
16
+ `Placeholder bindings are still in use for "counter.${method}".`,
17
+ CaatingaErrorCode.PLACEHOLDER_BINDING,
18
+ GENERATE_HINT
19
+ );
20
+ }
21
+
22
+ export class Client {
23
+ constructor(
24
+ private readonly input: {
25
+ contractId: string;
26
+ publicKey: string;
27
+ rpcUrl: string;
28
+ networkPassphrase: string;
29
+ }
30
+ ) {}
31
+
32
+ increment(): never {
33
+ return placeholderBinding("increment");
34
+ }
35
+
36
+ get(): never {
37
+ return placeholderBinding("get");
38
+ }
39
+
40
+ describe(): string {
41
+ return `${this.input.contractId}:${this.input.publicKey}`;
42
+ }
43
+ }
@@ -1,58 +0,0 @@
1
- type TransactionResult = {
2
- txHash: string;
3
- result?: unknown;
4
- };
5
-
6
- type SignTransaction = (
7
- xdr: string,
8
- opts?: { networkPassphrase?: string; address?: string }
9
- ) => Promise<{ signedTxXdr: string }> | { signedTxXdr: string };
10
-
11
- class ExampleTransaction {
12
- constructor(
13
- private readonly method: string,
14
- private readonly result?: unknown
15
- ) {}
16
-
17
- toXDR(): string {
18
- return `example-${this.method}-xdr`;
19
- }
20
-
21
- async prepare(): Promise<ExampleTransaction> {
22
- return this;
23
- }
24
-
25
- async signAndSend(input?: { signTransaction?: SignTransaction }): Promise<TransactionResult> {
26
- const signed = input?.signTransaction
27
- ? await input.signTransaction(this.toXDR())
28
- : { signedTxXdr: this.toXDR() };
29
-
30
- return {
31
- txHash: `example-transaction-hash:${signed.signedTxXdr}`,
32
- result: this.result
33
- };
34
- }
35
- }
36
-
37
- export class Client {
38
- constructor(
39
- private readonly input: {
40
- contractId: string;
41
- publicKey: string;
42
- rpcUrl: string;
43
- networkPassphrase: string;
44
- }
45
- ) {}
46
-
47
- increment(): ExampleTransaction {
48
- return new ExampleTransaction("increment", 1);
49
- }
50
-
51
- get(): ExampleTransaction {
52
- return new ExampleTransaction("get", 1);
53
- }
54
-
55
- describe(): string {
56
- return `${this.input.contractId}:${this.input.publicKey}`;
57
- }
58
- }