#!/usr/bin/env node "use strict"; const fs = require("fs"); const path = require("path"); const { PublicKey, Keypair, clusterApiUrl } = require("@solana/web3.js"); const { InstructionData, AccountMetaData } = require("@solana/spl-governance"); function parseEnvConfig(configPath) { const raw = fs.readFileSync(configPath, "utf8"); const out = {}; for (const line of raw.split("\n")) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith("#")) continue; const eq = trimmed.indexOf("="); if (eq < 0) continue; const key = trimmed.slice(0, eq).trim(); let value = trimmed.slice(eq + 1).trim(); if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { value = value.slice(1, -1); } value = value.replace(/\$HOME/g, process.env.HOME || ""); out[key] = value; } return out; } function resolveConfigPath(argvPath, fallbackName) { return argvPath ? path.resolve(argvPath) : path.resolve(__dirname, "..", fallbackName); } function loadKeypair(filePath) { const arr = JSON.parse(fs.readFileSync(filePath, "utf8")); return Keypair.fromSecretKey(Uint8Array.from(arr)); } function clusterUrl(cluster) { if (cluster === "devnet" || cluster === "mainnet-beta" || cluster === "testnet") { return clusterApiUrl(cluster); } return cluster; } function nowStamp() { const d = new Date(); const p = (n) => String(n).padStart(2, "0"); return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}_${p(d.getHours())}-${p(d.getMinutes())}-${p(d.getSeconds())}`; } function ensureArweaveUri(name, uri) { if (!uri) throw new Error(`${name} пустой`); if (!(uri.startsWith("https://arweave.net/") || uri.startsWith("ar://"))) { throw new Error(`${name} должен указывать на Arweave`); } } function assertRequired(cfg, key) { if (!cfg[key]) throw new Error(`В конфиге отсутствует обязательный параметр: ${key}`); } function toInstructionData(ix) { return new InstructionData({ programId: ix.programId, accounts: ix.keys.map( (k) => new AccountMetaData({ pubkey: k.pubkey, isSigner: !!k.isSigner, isWritable: !!k.isWritable, }) ), data: Uint8Array.from(ix.data), }); } function ensureDir(dirPath) { fs.mkdirSync(dirPath, { recursive: true }); } module.exports = { PublicKey, assertRequired, clusterUrl, ensureArweaveUri, ensureDir, loadKeypair, nowStamp, parseEnvConfig, resolveConfigPath, toInstructionData, };