@stellar/stellar-sdk
Version:
A library for working with the Stellar network, including communication with the Horizon and Soroban RPC servers.
183 lines (177 loc) • 6.47 kB
JavaScript
;
var commander = require('commander');
var path = require('path');
var wasm_fetcher = require('../bindings/wasm_fetcher.js');
var util = require('./util.js');
var network = require('../base/network.js');
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var path__namespace = /*#__PURE__*/_interopNamespace(path);
const NETWORK_CONFIG = {
testnet: {
passphrase: network.Networks.TESTNET,
rpcUrl: "https://soroban-testnet.stellar.org"
},
mainnet: {
passphrase: network.Networks.PUBLIC,
rpcUrl: null
// User must provide their own
},
futurenet: {
passphrase: network.Networks.FUTURENET,
rpcUrl: "https://rpc-futurenet.stellar.org"
},
localnet: {
passphrase: network.Networks.STANDALONE,
rpcUrl: "http://localhost:8000/rpc"
}
};
function runCli() {
const program = new commander.Command();
program.name("stellar-cli").description("CLI for generating TypeScript bindings for Stellar contracts").version("1.0.0");
program.command("generate").description("Generate TypeScript bindings for a Stellar contract").helpOption("-h, --help", "Display help for command").option("--wasm <path>", "Path to local WASM file").option("--wasm-hash <hash>", "Hash of WASM blob on network").option("--contract-id <id>", "Contract ID on network").option("--rpc-url <url>", "RPC server URL").option(
"--network <network>",
"Network options to use: mainnet, testnet, futurenet, or localnet"
).option("--output-dir <dir>", "Output directory for generated bindings").option(
"--allow-http",
"Allow insecure HTTP connections to RPC server",
false
).option("--timeout <ms>", "RPC request timeout in milliseconds").option(
"--headers <json>",
`Custom headers as JSON object (e.g., '{"Authorization": "Bearer token"}')`
).option(
"--contract-name <name>",
"Name for the generated contract client class"
).option("--overwrite", "Overwrite existing files", false).action(async (options) => {
try {
let networkPassphrase;
let rpcUrl = options.rpcUrl;
let allowHttp = options.allowHttp;
if (options.network) {
const network = options.network.toLowerCase();
const config = NETWORK_CONFIG[network];
if (!config) {
throw new Error(
`
\u2717 Invalid network: ${options.network}. Must be mainnet, testnet, futurenet, or localnet`
);
}
networkPassphrase = config.passphrase;
const needsRpcUrl = options.wasmHash || options.contractId;
if (!rpcUrl && needsRpcUrl) {
if (config.rpcUrl) {
rpcUrl = config.rpcUrl;
console.log(`Using default RPC URL for ${network}: ${rpcUrl}`);
if (network === "localnet" && !options.allowHttp) {
allowHttp = true;
}
} else if (network === "mainnet") {
throw new Error(
`
\u2717 --rpc-url is required for mainnet. Find RPC providers at: https://developers.stellar.org/docs/data/rpc/rpc-providers`
);
}
}
}
if (options.outputDir === void 0) {
throw new Error("Output directory (--output-dir) is required");
}
let headers;
if (options.headers) {
try {
headers = JSON.parse(options.headers);
} catch {
throw new Error(`Invalid JSON for --headers: ${options.headers}`);
}
}
let timeout;
if (options.timeout) {
timeout = parseInt(options.timeout, 10);
if (!/^\d+$/.test(options.timeout.trim()) || timeout <= 0) {
throw new Error(
`Invalid timeout value: ${options.timeout}. Must be a positive integer.`
);
}
}
console.log("Fetching contract...");
const { generator, source } = await util.createGenerator({
wasm: options.wasm,
wasmHash: options.wasmHash,
contractId: options.contractId,
rpcUrl,
networkPassphrase,
serverOptions: { allowHttp, timeout, headers }
});
util.logSourceInfo(source);
const contractName = options.contractName || util.deriveContractName(source) || "contract";
console.log(
`
\u2713 Generating TypeScript bindings for "${contractName}"...`
);
const bindings = await util.generateAndWrite(generator, {
contractName,
outputDir: path__namespace.resolve(options.outputDir),
overwrite: options.overwrite
});
for (const d of bindings.diagnostics) {
if (d.declarations > 1) {
console.warn(
`
\u26A0 Event "${d.rawName}" is declared ${d.declarations} times; declaration ${d.occurrence + 1} generated as ${d.interfaceName} with filter ${d.filterMethodName}(). Review the generated bindings to confirm which declaration you need.`
);
} else {
const renamed = [
...d.interfaceRenamed ? [d.interfaceName] : [],
...d.filterMethodRenamed ? [`${d.filterMethodName}()`] : []
];
console.warn(
`
\u26A0 Event "${d.rawName}": generated name${renamed.length > 1 ? "s" : ""} ${renamed.join(" and ")} ${renamed.length > 1 ? "were" : "was"} renamed to avoid a collision with another generated name.`
);
}
}
console.log(
`
\u2713 Successfully generated bindings in ${options.outputDir}`
);
console.log(`
Usage:`);
console.log(
` import { Client } from './${path__namespace.basename(options.outputDir)}';`
);
} catch (error) {
if (error instanceof wasm_fetcher.WasmFetchError) {
console.error(`
\u2717 Error: ${error.message}`);
if (error.cause) {
console.error(` Caused by: ${error.cause.message}`);
}
} else if (error instanceof Error) {
console.error(`
\u2717 Error: ${error.message}`);
} else {
console.error(`
\u2717 Unexpected error:`, error);
}
process.exit(1);
}
});
program.parse();
}
exports.runCli = runCli;
//# sourceMappingURL=index.js.map