@offckb/cli 0.4.8 → 0.4.9-canary-2b6b3af.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.
Files changed (3) hide show
  1. package/README.md +40 -0
  2. package/build/index.js +1553 -202
  3. package/package.json +1 -1
package/build/index.js CHANGED
@@ -235,16 +235,23 @@ exports.defaultSettings = {
235
235
  transactionsPath: path.resolve(exports.dataPath, 'mainnet/transactions'),
236
236
  },
237
237
  tools: {
238
+ rootFolder: path.resolve(exports.dataPath, 'tools'),
238
239
  ckbDebugger: {
239
240
  minVersion: '0.200.0',
240
241
  },
242
+ ckbTui: {
243
+ version: 'v0.1.3',
244
+ },
241
245
  },
242
246
  };
243
247
  function readSettings() {
244
248
  try {
245
249
  if (fs.existsSync(exports.configPath)) {
246
250
  const data = fs.readFileSync(exports.configPath, 'utf8');
247
- return deepMerge(exports.defaultSettings, JSON.parse(data));
251
+ const parsed = JSON.parse(data);
252
+ validateSettings(parsed);
253
+ // Deep-clone defaults before merging to prevent mutation of the shared default
254
+ return deepMerge(deepClone(exports.defaultSettings), parsed);
248
255
  }
249
256
  else {
250
257
  return exports.defaultSettings;
@@ -274,10 +281,26 @@ function getCKBBinaryPath(version) {
274
281
  const binaryName = platform === 'win32' ? 'ckb.exe' : 'ckb';
275
282
  return path.join(getCKBBinaryInstallPath(version), binaryName);
276
283
  }
284
+ function deepClone(obj) {
285
+ if (obj === null || typeof obj !== 'object') {
286
+ return obj;
287
+ }
288
+ if (Array.isArray(obj)) {
289
+ return obj.map(deepClone);
290
+ }
291
+ const clone = {};
292
+ for (const key in obj) {
293
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
294
+ clone[key] = deepClone(obj[key]);
295
+ }
296
+ }
297
+ return clone;
298
+ }
299
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
277
300
  function deepMerge(target, source) {
278
301
  for (const key in source) {
279
- if (source[key] && typeof source[key] === 'object') {
280
- if (!target[key]) {
302
+ if (source[key] !== null && typeof source[key] === 'object' && !Array.isArray(source[key])) {
303
+ if (!target[key] || typeof target[key] !== 'object') {
281
304
  target[key] = {};
282
305
  }
283
306
  deepMerge(target[key], source[key]);
@@ -288,6 +311,29 @@ function deepMerge(target, source) {
288
311
  }
289
312
  return target;
290
313
  }
314
+ function validateSettings(raw) {
315
+ if (!raw || typeof raw !== 'object') {
316
+ throw new Error('Settings must be a JSON object');
317
+ }
318
+ const obj = raw;
319
+ if (obj.tools && typeof obj.tools === 'object') {
320
+ const tools = obj.tools;
321
+ if (tools.rootFolder !== undefined && typeof tools.rootFolder !== 'string') {
322
+ throw new Error('tools.rootFolder must be a string path');
323
+ }
324
+ if (tools.ckbTui && typeof tools.ckbTui === 'object') {
325
+ const ckbTui = tools.ckbTui;
326
+ if (ckbTui.version !== undefined && typeof ckbTui.version !== 'string') {
327
+ throw new Error('tools.ckbTui.version must be a string');
328
+ }
329
+ }
330
+ }
331
+ if (obj.proxy !== undefined && obj.proxy !== null) {
332
+ if (typeof obj.proxy !== 'object') {
333
+ throw new Error('proxy must be an object');
334
+ }
335
+ }
336
+ }
291
337
 
292
338
 
293
339
  /***/ }),
@@ -316,6 +362,7 @@ const deposit_1 = __nccwpck_require__(48598);
316
362
  const deploy_1 = __nccwpck_require__(79617);
317
363
  const transfer_1 = __nccwpck_require__(40265);
318
364
  const balance_1 = __nccwpck_require__(77640);
365
+ const udt_1 = __nccwpck_require__(50703);
319
366
  const create_1 = __nccwpck_require__(51534);
320
367
  const config_1 = __nccwpck_require__(93004);
321
368
  const devnet_config_1 = __nccwpck_require__(10015);
@@ -325,20 +372,34 @@ const transfer_all_1 = __nccwpck_require__(92039);
325
372
  const gen_1 = __nccwpck_require__(750);
326
373
  const ckb_debugger_1 = __nccwpck_require__(14815);
327
374
  const logger_1 = __nccwpck_require__(65370);
375
+ const status_1 = __nccwpck_require__(71420);
376
+ const validator_1 = __nccwpck_require__(39534);
328
377
  const version = (__nccwpck_require__(8330)/* .version */ .rE);
329
378
  const description = (__nccwpck_require__(8330)/* .description */ .h_);
330
379
  // fix windows terminal encoding of simplified chinese text
331
380
  (0, encoding_1.setUTF8EncodingForWindows)();
332
381
  const program = new commander_1.Command();
333
382
  program.name('offckb').description(description).version(version).enablePositionalOptions();
334
- program
383
+ program.option('--json', 'Output logs in JSON format for agent/programmatic consumption');
384
+ program.hook('preAction', (thisCommand) => {
385
+ const opts = thisCommand.opts();
386
+ if (opts.json) {
387
+ logger_1.logger.setJsonMode(true);
388
+ }
389
+ });
390
+ const nodeCommand = program
335
391
  .command('node [CKB-Version]')
336
392
  .description('Use the CKB to start devnet')
337
393
  .option('--network <network>', 'Specify the network to deploy to', 'devnet')
338
394
  .option('-b, --binary-path <binaryPath>', 'Specify the CKB binary path to use, only for devnet, when set, will ignore version and network')
395
+ .option('--daemon', 'Run the node in the background as a daemon (devnet only)')
339
396
  .action((version, options) => __awaiter(void 0, void 0, void 0, function* () {
340
- return (0, node_1.startNode)({ version, network: options.network, binaryPath: options.binaryPath });
397
+ return (0, node_1.startNode)({ version, network: options.network, binaryPath: options.binaryPath, daemon: options.daemon });
341
398
  }));
399
+ nodeCommand
400
+ .command('stop')
401
+ .description('Stop the running CKB devnet daemon')
402
+ .action(() => __awaiter(void 0, void 0, void 0, function* () { return (0, node_1.stopNode)(); }));
342
403
  program
343
404
  .command('create [project-name]')
344
405
  .description('Create a new CKB Smart Contract project in JavaScript.')
@@ -412,13 +473,15 @@ program
412
473
  return (0, deposit_1.deposit)(toAddress, amountInCKB, options);
413
474
  }));
414
475
  program
415
- .command('transfer [toAddress] [amountInCKB]')
416
- .description('Transfer CKB tokens to address, only devnet and testnet')
476
+ .command('transfer [toAddress] [amount]')
477
+ .description('Transfer CKB or UDT tokens to address, only devnet and testnet')
417
478
  .option('--network <network>', 'Specify the network to transfer to', 'devnet')
418
- .option('--privkey <privkey>', 'Specify the private key to transfer CKB')
479
+ .option('--privkey <privkey>', 'Specify the private key to transfer')
480
+ .addOption(new commander_1.Option('--udt-kind <kind>', 'Specify the UDT kind').choices(['sudt', 'xudt']).default('sudt'))
481
+ .option('--udt-type-args <typeArgs>', 'Specify the UDT type script args to transfer UDT')
419
482
  .option('-r, --proxy-rpc', 'Use Proxy RPC to connect to blockchain')
420
- .action((toAddress, amountInCKB, options) => __awaiter(void 0, void 0, void 0, function* () {
421
- return (0, transfer_1.transfer)(toAddress, amountInCKB, options);
483
+ .action((toAddress, amount, options) => __awaiter(void 0, void 0, void 0, function* () {
484
+ return (0, transfer_1.transfer)(toAddress, amount, options);
422
485
  }));
423
486
  program
424
487
  .command('transfer-all [toAddress]')
@@ -431,11 +494,36 @@ program
431
494
  }));
432
495
  program
433
496
  .command('balance [toAddress]')
434
- .description('Check account balance, only devnet and testnet')
497
+ .description('Check account balance (CKB + detected SUDT/xUDT), only devnet and testnet')
435
498
  .option('--network <network>', 'Specify the network to check', 'devnet')
499
+ .addOption(new commander_1.Option('--udt-kind <kind>', 'Filter by UDT kind').choices(['sudt', 'xudt']))
500
+ .option('--udt-type-args <typeArgs>', 'Filter by UDT type script args')
501
+ .option('--no-udt', 'Skip UDT balance scan')
436
502
  .action((toAddress, options) => __awaiter(void 0, void 0, void 0, function* () {
437
503
  return (0, balance_1.balanceOf)(toAddress, options);
438
504
  }));
505
+ const udtCommand = program.command('udt').description('UDT token commands');
506
+ udtCommand
507
+ .command('issue <amount>')
508
+ .description('Issue new UDT tokens, only devnet and testnet')
509
+ .option('--network <network>', 'Specify the network', 'devnet')
510
+ .addOption(new commander_1.Option('--udt-kind <kind>', 'Specify the UDT kind').choices(['sudt', 'xudt']).default('sudt'))
511
+ .option('--type-args <typeArgs>', 'Specify the UDT type script args (xudt only; defaults to signer lock hash)')
512
+ .option('--to <toAddress>', 'Specify the receiver address (defaults to signer)')
513
+ .option('--privkey <privkey>', 'Specify the private key to issue UDT')
514
+ .action((amount, options) => __awaiter(void 0, void 0, void 0, function* () {
515
+ return (0, udt_1.udtIssue)(amount, options);
516
+ }));
517
+ udtCommand
518
+ .command('destroy <amount>')
519
+ .description('Destroy UDT tokens, only devnet and testnet')
520
+ .option('--network <network>', 'Specify the network', 'devnet')
521
+ .addOption(new commander_1.Option('--udt-kind <kind>', 'Specify the UDT kind').choices(['sudt', 'xudt']).default('sudt'))
522
+ .requiredOption('--type-args <typeArgs>', 'Specify the UDT type script args')
523
+ .option('--privkey <privkey>', 'Specify the private key to destroy UDT')
524
+ .action((amount, options) => __awaiter(void 0, void 0, void 0, function* () {
525
+ return (0, udt_1.udtDestroy)(amount, options);
526
+ }));
439
527
  program
440
528
  .command('debugger')
441
529
  .description('Port of the raw CKB Standalone Debugger')
@@ -445,6 +533,14 @@ program
445
533
  .action(() => __awaiter(void 0, void 0, void 0, function* () {
446
534
  return ckb_debugger_1.CKBDebugger.runWithArgs(process.argv.slice(2));
447
535
  }));
536
+ program
537
+ .command('status')
538
+ .description('Show ckb-tui status interface')
539
+ .option('--network <network>', 'Specify the network whose node status to monitor', 'devnet')
540
+ .action((option) => __awaiter(void 0, void 0, void 0, function* () {
541
+ (0, validator_1.validateNetworkOpt)(option.network);
542
+ return yield (0, status_1.status)({ network: option.network });
543
+ }));
448
544
  program
449
545
  .command('config <action> [item] [value]')
450
546
  .description('do a configuration action')
@@ -534,11 +630,31 @@ function balanceOf(address_1) {
534
630
  const network = opt.network;
535
631
  (0, validator_1.validateNetworkOpt)(network);
536
632
  const ckb = new ckb_1.CKB({ network });
537
- const balanceInCKB = yield ckb.balance(address);
538
- logger_1.logger.info(`Balance: ${balanceInCKB} CKB`);
633
+ const [balanceInCKB, udtBalances] = yield Promise.all([
634
+ ckb.balance(address),
635
+ opt.udt !== false ? ckb.detectUdtBalances(address) : Promise.resolve([]),
636
+ ]);
637
+ logger_1.logger.info(`CKB: ${balanceInCKB}`);
638
+ const filtered = filterUdtBalances(udtBalances, opt);
639
+ if (filtered.length > 0) {
640
+ logger_1.logger.info('UDT:');
641
+ for (const udt of filtered) {
642
+ logger_1.logger.info(` ${udt.kind} (args=${udt.args}): ${udt.balance}`);
643
+ }
644
+ }
539
645
  process.exit(0);
540
646
  });
541
647
  }
648
+ function filterUdtBalances(balances, opt) {
649
+ if (!opt.udtKind && !opt.udtTypeArgs) {
650
+ return balances;
651
+ }
652
+ return balances.filter((udt) => {
653
+ const kindMatch = opt.udtKind ? udt.kind === opt.udtKind : true;
654
+ const argsMatch = opt.udtTypeArgs ? udt.args === opt.udtTypeArgs : true;
655
+ return kindMatch && argsMatch;
656
+ });
657
+ }
542
658
 
543
659
 
544
660
  /***/ }),
@@ -1400,6 +1516,39 @@ function devnetConfig() {
1400
1516
 
1401
1517
  "use strict";
1402
1518
 
1519
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
1520
+ if (k2 === undefined) k2 = k;
1521
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1522
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1523
+ desc = { enumerable: true, get: function() { return m[k]; } };
1524
+ }
1525
+ Object.defineProperty(o, k2, desc);
1526
+ }) : (function(o, m, k, k2) {
1527
+ if (k2 === undefined) k2 = k;
1528
+ o[k2] = m[k];
1529
+ }));
1530
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
1531
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
1532
+ }) : function(o, v) {
1533
+ o["default"] = v;
1534
+ });
1535
+ var __importStar = (this && this.__importStar) || (function () {
1536
+ var ownKeys = function(o) {
1537
+ ownKeys = Object.getOwnPropertyNames || function (o) {
1538
+ var ar = [];
1539
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
1540
+ return ar;
1541
+ };
1542
+ return ownKeys(o);
1543
+ };
1544
+ return function (mod) {
1545
+ if (mod && mod.__esModule) return mod;
1546
+ var result = {};
1547
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
1548
+ __setModuleDefault(result, mod);
1549
+ return result;
1550
+ };
1551
+ })();
1403
1552
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
1404
1553
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1405
1554
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -1412,9 +1561,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
1412
1561
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1413
1562
  exports.startNode = startNode;
1414
1563
  exports.nodeDevnet = nodeDevnet;
1564
+ exports.stopNode = stopNode;
1415
1565
  exports.nodeTestnet = nodeTestnet;
1416
1566
  exports.nodeMainnet = nodeMainnet;
1417
1567
  const child_process_1 = __nccwpck_require__(35317);
1568
+ const fs = __importStar(__nccwpck_require__(79896));
1569
+ const path = __importStar(__nccwpck_require__(16928));
1418
1570
  const init_chain_1 = __nccwpck_require__(1360);
1419
1571
  const install_1 = __nccwpck_require__(65611);
1420
1572
  const setting_1 = __nccwpck_require__(25546);
@@ -1422,13 +1574,20 @@ const encoding_1 = __nccwpck_require__(6851);
1422
1574
  const rpc_proxy_1 = __nccwpck_require__(46589);
1423
1575
  const base_1 = __nccwpck_require__(69951);
1424
1576
  const logger_1 = __nccwpck_require__(65370);
1425
- function startNode({ version, network = base_1.Network.devnet, binaryPath }) {
1577
+ const DAEMON_LOG_DIR = 'logs';
1578
+ const DAEMON_LOG_FILE = 'daemon.log';
1579
+ const DAEMON_PID_FILE = 'daemon.pid';
1580
+ const DAEMON_CHILD_ENV = 'OFFCKB_DAEMON_CHILD';
1581
+ function startNode({ version, network = base_1.Network.devnet, binaryPath, daemon }) {
1426
1582
  if (binaryPath && network !== base_1.Network.devnet) {
1427
1583
  logger_1.logger.warn('Custom binaryPath is only supported for devnet. The provided binaryPath will be ignored.');
1428
1584
  }
1585
+ if (daemon && network !== base_1.Network.devnet) {
1586
+ logger_1.logger.warn('Daemon mode is only supported for devnet. The daemon flag will be ignored.');
1587
+ }
1429
1588
  switch (network) {
1430
1589
  case base_1.Network.devnet:
1431
- return nodeDevnet({ version, binaryPath });
1590
+ return nodeDevnet({ version, binaryPath, daemon });
1432
1591
  case base_1.Network.testnet:
1433
1592
  return nodeTestnet();
1434
1593
  case base_1.Network.mainnet:
@@ -1438,8 +1597,11 @@ function startNode({ version, network = base_1.Network.devnet, binaryPath }) {
1438
1597
  }
1439
1598
  }
1440
1599
  function nodeDevnet(_a) {
1441
- return __awaiter(this, arguments, void 0, function* ({ version, binaryPath }) {
1600
+ return __awaiter(this, arguments, void 0, function* ({ version, binaryPath, daemon }) {
1442
1601
  var _b, _c;
1602
+ if (daemon) {
1603
+ return startDaemon();
1604
+ }
1443
1605
  const settings = (0, setting_1.readSettings)();
1444
1606
  const ckbVersion = version || settings.bins.defaultCKBVersion;
1445
1607
  let ckbBinPath = '';
@@ -1494,6 +1656,314 @@ function nodeDevnet(_a) {
1494
1656
  }
1495
1657
  });
1496
1658
  }
1659
+ function resolveDaemonPaths() {
1660
+ const settings = (0, setting_1.readSettings)();
1661
+ const logDir = path.join(settings.devnet.dataPath, DAEMON_LOG_DIR);
1662
+ const logFile = path.join(logDir, DAEMON_LOG_FILE);
1663
+ const pidFile = path.join(logDir, DAEMON_PID_FILE);
1664
+ return { logDir, logFile, pidFile };
1665
+ }
1666
+ function readPidFile(pidFile) {
1667
+ var _a, _b;
1668
+ let raw;
1669
+ try {
1670
+ raw = fs.readFileSync(pidFile, 'utf8').trim();
1671
+ }
1672
+ catch (error) {
1673
+ // Treat a missing or unreadable PID file as "no daemon".
1674
+ return null;
1675
+ }
1676
+ if (!raw) {
1677
+ return null;
1678
+ }
1679
+ // Backward compatibility: plain integer PID written by older versions.
1680
+ const plainPid = Number(raw);
1681
+ if (Number.isInteger(plainPid) && plainPid > 0) {
1682
+ return { pid: plainPid, scriptPath: (_a = resolveCliEntry()) !== null && _a !== void 0 ? _a : '', startedAt: new Date(0).toISOString() };
1683
+ }
1684
+ try {
1685
+ const parsed = JSON.parse(raw);
1686
+ const pid = Number(parsed.pid);
1687
+ if (Number.isInteger(pid) && pid > 0 && typeof parsed.scriptPath === 'string') {
1688
+ return {
1689
+ pid,
1690
+ scriptPath: parsed.scriptPath,
1691
+ startedAt: (_b = parsed.startedAt) !== null && _b !== void 0 ? _b : new Date(0).toISOString(),
1692
+ };
1693
+ }
1694
+ }
1695
+ catch (_c) {
1696
+ // fall through to sentinel below
1697
+ }
1698
+ // Content exists but is neither a valid plain PID nor valid metadata.
1699
+ // Return a sentinel so stopNode can report an invalid PID and clean up.
1700
+ return { pid: NaN, scriptPath: '', startedAt: new Date(0).toISOString() };
1701
+ }
1702
+ function writePidFile(pidFile, metadata) {
1703
+ fs.writeFileSync(pidFile, JSON.stringify(metadata, null, 2));
1704
+ }
1705
+ function resolveCliEntry() {
1706
+ var _a;
1707
+ // In priority order. process.argv[1] is the most reliable for a Node CLI.
1708
+ // OFFCKB_CLI_PATH is an escape hatch for packaged/npx/weird environments.
1709
+ // require.main?.filename is a final fallback when argv is unavailable.
1710
+ const candidates = [process.env.OFFCKB_CLI_PATH, process.argv[1], (_a = require.main) === null || _a === void 0 ? void 0 : _a.filename].filter((c) => typeof c === 'string' && c.length > 0);
1711
+ for (const candidate of candidates) {
1712
+ try {
1713
+ const resolved = path.resolve(candidate);
1714
+ const stats = fs.statSync(resolved);
1715
+ if (stats.isFile()) {
1716
+ return resolved;
1717
+ }
1718
+ }
1719
+ catch (_b) {
1720
+ // Candidate is missing or not a file; try the next one.
1721
+ }
1722
+ }
1723
+ return null;
1724
+ }
1725
+ function isProcessAlive(pid) {
1726
+ try {
1727
+ process.kill(pid, 0);
1728
+ return true;
1729
+ }
1730
+ catch (_a) {
1731
+ return false;
1732
+ }
1733
+ }
1734
+ function cleanupPidFile(pidFile) {
1735
+ try {
1736
+ fs.unlinkSync(pidFile);
1737
+ }
1738
+ catch (error) {
1739
+ logger_1.logger.warn(`Failed to remove PID file ${pidFile}:`, error);
1740
+ }
1741
+ }
1742
+ function waitForProcessExit(pid, timeoutMs) {
1743
+ const start = Date.now();
1744
+ return new Promise((resolve) => {
1745
+ const check = () => {
1746
+ if (!isProcessAlive(pid)) {
1747
+ resolve(true);
1748
+ return;
1749
+ }
1750
+ if (Date.now() - start >= timeoutMs) {
1751
+ resolve(false);
1752
+ return;
1753
+ }
1754
+ setTimeout(check, 100);
1755
+ };
1756
+ check();
1757
+ });
1758
+ }
1759
+ function getProcessCommandLine(pid) {
1760
+ return new Promise((resolve) => {
1761
+ if (process.platform === 'win32') {
1762
+ (0, child_process_1.exec)(`wmic process where ProcessId=${pid} get CommandLine /format:list`, (error, stdout) => {
1763
+ if (error) {
1764
+ resolve(null);
1765
+ return;
1766
+ }
1767
+ const match = stdout.match(/CommandLine=(.+)/);
1768
+ resolve(match ? match[1].trim() : null);
1769
+ });
1770
+ }
1771
+ else {
1772
+ (0, child_process_1.exec)(`ps -p ${pid} -o args=`, (error, stdout) => {
1773
+ if (error) {
1774
+ resolve(null);
1775
+ return;
1776
+ }
1777
+ resolve(stdout.trim());
1778
+ });
1779
+ }
1780
+ });
1781
+ }
1782
+ function verifyDaemonIdentity(pid, metadata) {
1783
+ return __awaiter(this, void 0, void 0, function* () {
1784
+ const cmdline = yield getProcessCommandLine(pid);
1785
+ if (!cmdline) {
1786
+ return false;
1787
+ }
1788
+ // The daemon child re-runs the same CLI entry point, so its command line
1789
+ // should reference the same script and should be a Node process.
1790
+ const scriptName = path.basename(metadata.scriptPath);
1791
+ const scriptDir = path.dirname(metadata.scriptPath);
1792
+ const looksLikeNode = cmdline.includes('node') || cmdline.includes('nodejs');
1793
+ const looksLikeOurScript = cmdline.includes(metadata.scriptPath) || (scriptName !== '' && cmdline.includes(scriptName));
1794
+ const looksLikeOffckb = cmdline.includes('offckb') || scriptDir.includes('offckb');
1795
+ return looksLikeNode && (looksLikeOurScript || looksLikeOffckb);
1796
+ });
1797
+ }
1798
+ function terminateProcess(pid, signal) {
1799
+ return new Promise((resolve, reject) => {
1800
+ if (process.platform === 'win32') {
1801
+ // Windows has no POSIX signals and process.kill(pid) only terminates the
1802
+ // single process. Use taskkill to terminate the whole tree.
1803
+ // /T kills the process and all child processes.
1804
+ // /F forces termination when SIGKILL is requested.
1805
+ const args = signal === 'SIGKILL' ? ['/T', '/F', '/PID', String(pid)] : ['/T', '/PID', String(pid)];
1806
+ const taskkill = (0, child_process_1.spawn)('taskkill', args, { stdio: 'ignore' });
1807
+ taskkill.on('error', reject);
1808
+ taskkill.on('exit', () => {
1809
+ // taskkill may return non-zero if the process is already gone, which
1810
+ // is acceptable for our purposes.
1811
+ resolve();
1812
+ });
1813
+ return;
1814
+ }
1815
+ // On POSIX, detached: true makes the child a session/process group leader.
1816
+ // A negative pid sends the signal to the entire process group, ensuring
1817
+ // the CKB node, miner and RPC proxy all receive it.
1818
+ try {
1819
+ process.kill(-pid, signal);
1820
+ resolve();
1821
+ }
1822
+ catch (error) {
1823
+ reject(error);
1824
+ }
1825
+ });
1826
+ }
1827
+ function startDaemon() {
1828
+ const { logDir, logFile, pidFile } = resolveDaemonPaths();
1829
+ // Prevent duplicate daemon starts. If a daemon is already running, refuse
1830
+ // to overwrite its PID file.
1831
+ const existing = readPidFile(pidFile);
1832
+ if (existing && isProcessAlive(existing.pid)) {
1833
+ logger_1.logger.error(`A CKB devnet daemon is already running (PID ${existing.pid}). Stop it first with: offckb node stop`);
1834
+ return;
1835
+ }
1836
+ if (existing && !isProcessAlive(existing.pid)) {
1837
+ // Stale PID file from a crashed daemon; clean it up before starting anew.
1838
+ cleanupPidFile(pidFile);
1839
+ }
1840
+ let out;
1841
+ let err;
1842
+ try {
1843
+ fs.mkdirSync(logDir, { recursive: true });
1844
+ out = fs.openSync(logFile, 'a');
1845
+ err = fs.openSync(logFile, 'a');
1846
+ }
1847
+ catch (error) {
1848
+ logger_1.logger.error(`Failed to prepare daemon log directory or log file at ${logFile}:`, error);
1849
+ return;
1850
+ }
1851
+ const scriptPath = resolveCliEntry();
1852
+ if (!scriptPath) {
1853
+ logger_1.logger.error('Unable to determine the CLI entry point for daemon mode. Set OFFCKB_CLI_PATH to the offckb script.');
1854
+ closeFileDescriptors(out, err);
1855
+ return;
1856
+ }
1857
+ const childArgs = process.argv.slice(2).filter((arg) => arg !== '--daemon');
1858
+ const childEnv = Object.assign(Object.assign({}, process.env), { [DAEMON_CHILD_ENV]: '1' });
1859
+ let child;
1860
+ try {
1861
+ child = (0, child_process_1.spawn)(process.execPath, [scriptPath, ...childArgs], {
1862
+ detached: true,
1863
+ stdio: ['ignore', out, err],
1864
+ env: childEnv,
1865
+ });
1866
+ }
1867
+ catch (error) {
1868
+ logger_1.logger.error('Failed to spawn daemon process:', error);
1869
+ closeFileDescriptors(out, err);
1870
+ return;
1871
+ }
1872
+ if (!child.pid) {
1873
+ logger_1.logger.error('Failed to spawn daemon process: no PID returned.');
1874
+ closeFileDescriptors(out, err);
1875
+ return;
1876
+ }
1877
+ child.unref();
1878
+ child.on('error', (error) => {
1879
+ logger_1.logger.error('Daemon child process failed to start:', error);
1880
+ cleanupPidFile(pidFile);
1881
+ });
1882
+ const metadata = {
1883
+ pid: child.pid,
1884
+ scriptPath,
1885
+ startedAt: new Date().toISOString(),
1886
+ };
1887
+ writePidFile(pidFile, metadata);
1888
+ // File descriptors are now owned by the spawned child; close our copies.
1889
+ closeFileDescriptors(out, err);
1890
+ logger_1.logger.success(`CKB devnet daemon started with PID ${child.pid}.`);
1891
+ logger_1.logger.info(`Logs: ${logFile}`);
1892
+ logger_1.logger.info(`PID file: ${pidFile}`);
1893
+ logger_1.logger.info('Stop the daemon with: offckb node stop');
1894
+ }
1895
+ function closeFileDescriptors(...fds) {
1896
+ for (const fd of fds) {
1897
+ if (fd === undefined)
1898
+ continue;
1899
+ try {
1900
+ fs.closeSync(fd);
1901
+ }
1902
+ catch (_a) {
1903
+ // ignore
1904
+ }
1905
+ }
1906
+ }
1907
+ function stopNode() {
1908
+ return __awaiter(this, void 0, void 0, function* () {
1909
+ const { pidFile } = resolveDaemonPaths();
1910
+ const metadata = readPidFile(pidFile);
1911
+ if (!metadata) {
1912
+ logger_1.logger.warn(`No daemon PID file found at ${pidFile}. Is the devnet daemon running?`);
1913
+ return;
1914
+ }
1915
+ const pid = metadata.pid;
1916
+ if (!Number.isInteger(pid) || pid <= 0) {
1917
+ logger_1.logger.error(`Invalid PID in ${pidFile}: ${pid}`);
1918
+ cleanupPidFile(pidFile);
1919
+ return;
1920
+ }
1921
+ if (!isProcessAlive(pid)) {
1922
+ logger_1.logger.warn(`Daemon process ${pid} is not running.`);
1923
+ cleanupPidFile(pidFile);
1924
+ return;
1925
+ }
1926
+ const identityOk = yield verifyDaemonIdentity(pid, metadata);
1927
+ if (!identityOk) {
1928
+ logger_1.logger.error(`Process ${pid} does not appear to be the offckb daemon. Refusing to send signals to avoid killing an unrelated process. ` +
1929
+ `If you are sure this is the daemon, stop it manually and remove ${pidFile}.`);
1930
+ return;
1931
+ }
1932
+ logger_1.logger.info(`Stopping CKB devnet daemon (PID ${pid})...`);
1933
+ try {
1934
+ yield terminateProcess(pid, 'SIGTERM');
1935
+ }
1936
+ catch (error) {
1937
+ const err = error;
1938
+ if (err.code === 'ESRCH') {
1939
+ logger_1.logger.warn(`Daemon process ${pid} is not running.`);
1940
+ cleanupPidFile(pidFile);
1941
+ return;
1942
+ }
1943
+ if (err.code === 'EPERM') {
1944
+ logger_1.logger.error(`Permission denied when sending SIGTERM to daemon process ${pid}.`);
1945
+ }
1946
+ else {
1947
+ logger_1.logger.error(`Failed to send SIGTERM to daemon process ${pid}:`, error);
1948
+ }
1949
+ // Still try to clean up the PID file so the user can recover.
1950
+ cleanupPidFile(pidFile);
1951
+ return;
1952
+ }
1953
+ const exited = yield waitForProcessExit(pid, 5000);
1954
+ if (!exited) {
1955
+ logger_1.logger.warn(`Daemon process ${pid} did not exit gracefully, sending SIGKILL...`);
1956
+ try {
1957
+ yield terminateProcess(pid, 'SIGKILL');
1958
+ }
1959
+ catch (error) {
1960
+ logger_1.logger.error(`Failed to send SIGKILL to daemon process ${pid}:`, error);
1961
+ }
1962
+ }
1963
+ cleanupPidFile(pidFile);
1964
+ logger_1.logger.success('CKB devnet daemon stopped.');
1965
+ });
1966
+ }
1497
1967
  function nodeTestnet() {
1498
1968
  return __awaiter(this, void 0, void 0, function* () {
1499
1969
  // todo: maybe we can actually start a node for testnet later
@@ -1518,6 +1988,130 @@ function nodeMainnet() {
1518
1988
  }
1519
1989
 
1520
1990
 
1991
+ /***/ }),
1992
+
1993
+ /***/ 71420:
1994
+ /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
1995
+
1996
+ "use strict";
1997
+
1998
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
1999
+ if (k2 === undefined) k2 = k;
2000
+ var desc = Object.getOwnPropertyDescriptor(m, k);
2001
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
2002
+ desc = { enumerable: true, get: function() { return m[k]; } };
2003
+ }
2004
+ Object.defineProperty(o, k2, desc);
2005
+ }) : (function(o, m, k, k2) {
2006
+ if (k2 === undefined) k2 = k;
2007
+ o[k2] = m[k];
2008
+ }));
2009
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
2010
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
2011
+ }) : function(o, v) {
2012
+ o["default"] = v;
2013
+ });
2014
+ var __importStar = (this && this.__importStar) || (function () {
2015
+ var ownKeys = function(o) {
2016
+ ownKeys = Object.getOwnPropertyNames || function (o) {
2017
+ var ar = [];
2018
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
2019
+ return ar;
2020
+ };
2021
+ return ownKeys(o);
2022
+ };
2023
+ return function (mod) {
2024
+ if (mod && mod.__esModule) return mod;
2025
+ var result = {};
2026
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
2027
+ __setModuleDefault(result, mod);
2028
+ return result;
2029
+ };
2030
+ })();
2031
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2032
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
2033
+ return new (P || (P = Promise))(function (resolve, reject) {
2034
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
2035
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
2036
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
2037
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
2038
+ });
2039
+ };
2040
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2041
+ exports.status = status;
2042
+ const setting_1 = __nccwpck_require__(25546);
2043
+ const ckb_tui_1 = __nccwpck_require__(7020);
2044
+ const base_1 = __nccwpck_require__(69951);
2045
+ const logger_1 = __nccwpck_require__(65370);
2046
+ const net = __importStar(__nccwpck_require__(69278));
2047
+ const NETWORK_SETTINGS_KEY = {
2048
+ [base_1.Network.devnet]: 'devnet',
2049
+ [base_1.Network.testnet]: 'testnet',
2050
+ [base_1.Network.mainnet]: 'mainnet',
2051
+ };
2052
+ function status(_a) {
2053
+ return __awaiter(this, arguments, void 0, function* ({ network }) {
2054
+ var _b;
2055
+ // ckb-tui is an interactive terminal UI. Running it without a TTY
2056
+ // (pipe, redirect, CI) would hang or produce garbage output.
2057
+ if (!process.stdout.isTTY || !process.stdin.isTTY) {
2058
+ logger_1.logger.error('The status command requires an interactive terminal (TTY). ' +
2059
+ 'It cannot be used in pipes, redirects, or non-interactive environments like CI.');
2060
+ process.exit(1);
2061
+ }
2062
+ const settings = (0, setting_1.readSettings)();
2063
+ const networkKey = NETWORK_SETTINGS_KEY[network];
2064
+ const port = settings[networkKey].rpcProxyPort;
2065
+ const url = `http://127.0.0.1:${port}`;
2066
+ const isListening = yield isRPCPortListening(port);
2067
+ if (!isListening) {
2068
+ logger_1.logger.error(`RPC port ${port} is not listening. Please make sure the ${network} node is running and Proxy RPC is enabled.`);
2069
+ return;
2070
+ }
2071
+ const result = ckb_tui_1.CKBTui.run(['-r', url]);
2072
+ // Propagate ckb-tui exit code so scripts can detect TUI failure
2073
+ if (result.status !== 0) {
2074
+ process.exitCode = (_b = result.status) !== null && _b !== void 0 ? _b : 1;
2075
+ }
2076
+ });
2077
+ }
2078
+ function isRPCPortListening(port) {
2079
+ return __awaiter(this, void 0, void 0, function* () {
2080
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
2081
+ return false;
2082
+ }
2083
+ const client = new net.Socket();
2084
+ return new Promise((resolve) => {
2085
+ let settled = false;
2086
+ const TIMEOUT_MS = 2000;
2087
+ const timeout = setTimeout(() => {
2088
+ if (!settled) {
2089
+ settled = true;
2090
+ client.destroy();
2091
+ resolve(false);
2092
+ }
2093
+ }, TIMEOUT_MS);
2094
+ client.once('error', () => {
2095
+ if (!settled) {
2096
+ settled = true;
2097
+ clearTimeout(timeout);
2098
+ resolve(false);
2099
+ }
2100
+ });
2101
+ client.once('connect', () => {
2102
+ if (!settled) {
2103
+ settled = true;
2104
+ clearTimeout(timeout);
2105
+ client.end();
2106
+ resolve(true);
2107
+ }
2108
+ });
2109
+ client.connect(port, '127.0.0.1');
2110
+ });
2111
+ });
2112
+ }
2113
+
2114
+
1521
2115
  /***/ }),
1522
2116
 
1523
2117
  /***/ 86198:
@@ -1829,9 +2423,9 @@ const ckb_1 = __nccwpck_require__(83748);
1829
2423
  const base_1 = __nccwpck_require__(69951);
1830
2424
  const link_1 = __nccwpck_require__(27814);
1831
2425
  const validator_1 = __nccwpck_require__(39534);
1832
- const logger_1 = __nccwpck_require__(65370);
1833
- function transfer(toAddress_1, amountInCKB_1) {
1834
- return __awaiter(this, arguments, void 0, function* (toAddress, amountInCKB, opt = { network: base_1.Network.devnet }) {
2426
+ function transfer(toAddress_1, amount_1) {
2427
+ return __awaiter(this, arguments, void 0, function* (toAddress, amount, opt = { network: base_1.Network.devnet }) {
2428
+ var _a;
1835
2429
  const network = opt.network;
1836
2430
  (0, validator_1.validateNetworkOpt)(network);
1837
2431
  if (opt.privkey == null) {
@@ -1839,16 +2433,89 @@ function transfer(toAddress_1, amountInCKB_1) {
1839
2433
  }
1840
2434
  const privateKey = opt.privkey;
1841
2435
  const ckb = new ckb_1.CKB({ network });
2436
+ if (opt.udtTypeArgs) {
2437
+ const kind = (_a = opt.udtKind) !== null && _a !== void 0 ? _a : 'sudt';
2438
+ (0, validator_1.validateUdtKind)(kind);
2439
+ const udtTypeArgs = (0, validator_1.validateUdtTypeArgs)(kind, opt.udtTypeArgs);
2440
+ const udtType = yield ckb.buildUdtTypeScript(kind, udtTypeArgs);
2441
+ const txHash = yield ckb.udtTransfer({
2442
+ toAddress,
2443
+ amount,
2444
+ privateKey,
2445
+ udtType,
2446
+ kind,
2447
+ });
2448
+ (0, link_1.logTxSuccess)(network, txHash, 'transfer UDT');
2449
+ return;
2450
+ }
1842
2451
  const txHash = yield ckb.transfer({
1843
2452
  toAddress,
1844
- amountInCKB,
2453
+ amountInCKB: amount,
1845
2454
  privateKey,
1846
2455
  });
1847
- if (network === 'testnet') {
1848
- logger_1.logger.info(`Successfully transfer, check ${(0, link_1.buildTestnetTxLink)(txHash)} for details.`);
1849
- return;
2456
+ (0, link_1.logTxSuccess)(network, txHash, 'transfer');
2457
+ });
2458
+ }
2459
+
2460
+
2461
+ /***/ }),
2462
+
2463
+ /***/ 50703:
2464
+ /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
2465
+
2466
+ "use strict";
2467
+
2468
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2469
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
2470
+ return new (P || (P = Promise))(function (resolve, reject) {
2471
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
2472
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
2473
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
2474
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
2475
+ });
2476
+ };
2477
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2478
+ exports.udtIssue = udtIssue;
2479
+ exports.udtDestroy = udtDestroy;
2480
+ const ckb_1 = __nccwpck_require__(83748);
2481
+ const base_1 = __nccwpck_require__(69951);
2482
+ const link_1 = __nccwpck_require__(27814);
2483
+ const validator_1 = __nccwpck_require__(39534);
2484
+ function udtIssue(amount_1) {
2485
+ return __awaiter(this, arguments, void 0, function* (amount, opt = { network: base_1.Network.devnet, udtKind: 'sudt', privkey: '' }) {
2486
+ const network = opt.network;
2487
+ (0, validator_1.validateNetworkOpt)(network);
2488
+ (0, validator_1.validateUdtKind)(opt.udtKind);
2489
+ if (!opt.privkey) {
2490
+ throw new Error('--privkey is required!');
1850
2491
  }
1851
- logger_1.logger.info('Successfully transfer, txHash:', txHash);
2492
+ const ckb = new ckb_1.CKB({ network });
2493
+ const txHash = yield ckb.udtIssue({
2494
+ privateKey: opt.privkey,
2495
+ kind: opt.udtKind,
2496
+ amount,
2497
+ typeArgs: opt.typeArgs ? (0, validator_1.validateUdtTypeArgs)(opt.udtKind, opt.typeArgs) : undefined,
2498
+ toAddress: opt.to,
2499
+ });
2500
+ (0, link_1.logTxSuccess)(network, txHash, 'issued UDT');
2501
+ });
2502
+ }
2503
+ function udtDestroy(amount_1) {
2504
+ return __awaiter(this, arguments, void 0, function* (amount, opt = { network: base_1.Network.devnet, udtKind: 'sudt', typeArgs: '', privkey: '' }) {
2505
+ const network = opt.network;
2506
+ (0, validator_1.validateNetworkOpt)(network);
2507
+ (0, validator_1.validateUdtKind)(opt.udtKind);
2508
+ if (!opt.privkey) {
2509
+ throw new Error('--privkey is required!');
2510
+ }
2511
+ const ckb = new ckb_1.CKB({ network });
2512
+ const txHash = yield ckb.udtDestroy({
2513
+ privateKey: opt.privkey,
2514
+ kind: opt.udtKind,
2515
+ amount,
2516
+ typeArgs: (0, validator_1.validateUdtTypeArgs)(opt.udtKind, opt.typeArgs),
2517
+ });
2518
+ (0, link_1.logTxSuccess)(network, txHash, 'destroyed UDT');
1852
2519
  });
1853
2520
  }
1854
2521
 
@@ -3827,18 +4494,36 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
3827
4494
  step((generator = generator.apply(thisArg, _arguments || [])).next());
3828
4495
  });
3829
4496
  };
4497
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
4498
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
4499
+ var m = o[Symbol.asyncIterator], i;
4500
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
4501
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
4502
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
4503
+ };
3830
4504
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3831
4505
  exports.CKB = exports.CKBProps = void 0;
3832
4506
  const core_1 = __nccwpck_require__(39842);
3833
4507
  const validator_1 = __nccwpck_require__(39534);
3834
4508
  const network_1 = __nccwpck_require__(5370);
3835
4509
  const private_1 = __nccwpck_require__(5835);
4510
+ const public_1 = __nccwpck_require__(84535);
3836
4511
  const migration_1 = __nccwpck_require__(76679);
3837
4512
  const base_1 = __nccwpck_require__(69951);
3838
4513
  const logger_1 = __nccwpck_require__(65370);
4514
+ const DEFAULT_UDT_SCAN_MAX_CELLS = 1000;
4515
+ const DEFAULT_UDT_DESTROY_MAX_INPUT_CELLS = 100;
3839
4516
  class CKBProps {
3840
4517
  }
3841
4518
  exports.CKBProps = CKBProps;
4519
+ function readUdtBalance(outputData) {
4520
+ try {
4521
+ return BigInt(core_1.ccc.udtBalanceFrom(outputData));
4522
+ }
4523
+ catch (_a) {
4524
+ return null;
4525
+ }
4526
+ }
3842
4527
  class CKB {
3843
4528
  constructor({ network = base_1.Network.devnet, feeRate = 1000, isEnableProxyRpc = true }) {
3844
4529
  if (!(0, validator_1.isValidNetworkString)(network)) {
@@ -3972,6 +4657,286 @@ class CKB {
3972
4657
  return txHash;
3973
4658
  });
3974
4659
  }
4660
+ getSystemScripts() {
4661
+ if (this.network === base_1.Network.mainnet) {
4662
+ return public_1.MAINNET_SYSTEM_SCRIPTS;
4663
+ }
4664
+ if (this.network === base_1.Network.testnet) {
4665
+ return public_1.TESTNET_SYSTEM_SCRIPTS;
4666
+ }
4667
+ const scripts = (0, private_1.getDevnetSystemScriptsFromListHashes)();
4668
+ if (!scripts) {
4669
+ throw new Error(`Failed to load devnet system scripts`);
4670
+ }
4671
+ return scripts;
4672
+ }
4673
+ buildUdtTypeScript(kind, args) {
4674
+ return __awaiter(this, void 0, void 0, function* () {
4675
+ if (kind === 'xudt') {
4676
+ return core_1.ccc.Script.fromKnownScript(this.client, core_1.ccc.KnownScript.XUdt, args);
4677
+ }
4678
+ const scriptInfo = yield this.getUdtScriptInfo(kind);
4679
+ return core_1.ccc.Script.from({
4680
+ codeHash: scriptInfo.codeHash,
4681
+ hashType: scriptInfo.hashType,
4682
+ args,
4683
+ });
4684
+ });
4685
+ }
4686
+ getUdtScriptInfo(kind) {
4687
+ return __awaiter(this, void 0, void 0, function* () {
4688
+ var _a;
4689
+ if (kind === 'xudt') {
4690
+ return this.client.getKnownScript(core_1.ccc.KnownScript.XUdt);
4691
+ }
4692
+ const systemScripts = this.getSystemScripts();
4693
+ const sudtScript = (_a = systemScripts.sudt) === null || _a === void 0 ? void 0 : _a.script;
4694
+ if (!sudtScript) {
4695
+ throw new Error(`SUDT script not found on ${this.network}`);
4696
+ }
4697
+ return sudtScript;
4698
+ });
4699
+ }
4700
+ detectUdtBalances(address_1) {
4701
+ return __awaiter(this, arguments, void 0, function* (address, { maxCells = DEFAULT_UDT_SCAN_MAX_CELLS } = {}) {
4702
+ const lock = (yield core_1.ccc.Address.fromString(address, this.client)).script;
4703
+ const sudtScriptInfo = yield this.getUdtScriptInfo('sudt').catch(() => null);
4704
+ const xudtScriptInfo = yield this.getUdtScriptInfo('xudt').catch(() => null);
4705
+ const balances = new Map();
4706
+ let scanned = 0;
4707
+ const scan = (scriptInfo, kind) => __awaiter(this, void 0, void 0, function* () {
4708
+ var _a, e_1, _b, _c;
4709
+ var _d, _e;
4710
+ try {
4711
+ for (var _f = true, _g = __asyncValues(this.client.findCells({
4712
+ script: {
4713
+ codeHash: scriptInfo.codeHash,
4714
+ hashType: scriptInfo.hashType,
4715
+ args: '0x',
4716
+ },
4717
+ scriptType: 'type',
4718
+ scriptSearchMode: 'prefix',
4719
+ filter: { script: lock },
4720
+ withData: true,
4721
+ }, 'asc')), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
4722
+ _c = _h.value;
4723
+ _f = false;
4724
+ const cell = _c;
4725
+ if (scanned >= maxCells) {
4726
+ logger_1.logger.warn(`UDT balance scan stopped after ${maxCells} cells; balances may be incomplete`);
4727
+ break;
4728
+ }
4729
+ scanned++;
4730
+ const type = cell.cellOutput.type;
4731
+ if (!type) {
4732
+ continue;
4733
+ }
4734
+ const cellBalance = readUdtBalance(cell.outputData);
4735
+ if (cellBalance == null) {
4736
+ logger_1.logger.debug(`Skipping corrupted UDT cell ${(_d = cell.outPoint) === null || _d === void 0 ? void 0 : _d.txHash}:${(_e = cell.outPoint) === null || _e === void 0 ? void 0 : _e.index}`);
4737
+ continue;
4738
+ }
4739
+ const key = `${kind}:${type.codeHash}:${type.hashType}:${type.args}`;
4740
+ const entry = balances.get(key);
4741
+ if (entry) {
4742
+ entry.balance += cellBalance;
4743
+ }
4744
+ else {
4745
+ balances.set(key, {
4746
+ kind,
4747
+ codeHash: type.codeHash,
4748
+ hashType: String(type.hashType),
4749
+ args: type.args,
4750
+ balance: cellBalance,
4751
+ });
4752
+ }
4753
+ }
4754
+ }
4755
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
4756
+ finally {
4757
+ try {
4758
+ if (!_f && !_a && (_b = _g.return)) yield _b.call(_g);
4759
+ }
4760
+ finally { if (e_1) throw e_1.error; }
4761
+ }
4762
+ });
4763
+ if (sudtScriptInfo) {
4764
+ yield scan(sudtScriptInfo, 'sudt');
4765
+ }
4766
+ if (xudtScriptInfo) {
4767
+ yield scan(xudtScriptInfo, 'xudt');
4768
+ }
4769
+ return Array.from(balances.values()).map((item) => (Object.assign(Object.assign({}, item), { balance: item.balance.toString() })));
4770
+ });
4771
+ }
4772
+ udtBalance(address_1, udtType_1) {
4773
+ return __awaiter(this, arguments, void 0, function* (address, udtType, { maxCells = DEFAULT_UDT_SCAN_MAX_CELLS } = {}) {
4774
+ var _a, e_2, _b, _c;
4775
+ const lock = (yield core_1.ccc.Address.fromString(address, this.client)).script;
4776
+ let balance = BigInt(0);
4777
+ let scanned = 0;
4778
+ try {
4779
+ for (var _d = true, _e = __asyncValues(this.client.findCellsByLock(lock, udtType, true)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
4780
+ _c = _f.value;
4781
+ _d = false;
4782
+ const cell = _c;
4783
+ scanned++;
4784
+ if (scanned > maxCells) {
4785
+ logger_1.logger.warn(`UDT balance scan stopped after ${maxCells} cells; balances may be incomplete`);
4786
+ break;
4787
+ }
4788
+ const cellBalance = readUdtBalance(cell.outputData);
4789
+ if (cellBalance != null) {
4790
+ balance += cellBalance;
4791
+ }
4792
+ }
4793
+ }
4794
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
4795
+ finally {
4796
+ try {
4797
+ if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
4798
+ }
4799
+ finally { if (e_2) throw e_2.error; }
4800
+ }
4801
+ return balance.toString();
4802
+ });
4803
+ }
4804
+ udtTransfer(_a) {
4805
+ return __awaiter(this, arguments, void 0, function* ({ privateKey, toAddress, amount, udtType, kind }) {
4806
+ const signer = this.buildSigner(privateKey);
4807
+ const to = yield core_1.ccc.Address.fromString(toAddress, this.client);
4808
+ const amountBigInt = (0, validator_1.validateUdtAmount)(amount);
4809
+ const outputsData = [core_1.ccc.hexFrom(core_1.ccc.numToBytes(amountBigInt, 16))];
4810
+ const tx = core_1.ccc.Transaction.from({
4811
+ outputs: [
4812
+ {
4813
+ lock: to.script,
4814
+ type: udtType,
4815
+ capacity: core_1.ccc.fixedPointFrom(0),
4816
+ },
4817
+ ],
4818
+ outputsData,
4819
+ });
4820
+ const scriptInfo = yield this.getUdtScriptInfo(kind);
4821
+ tx.addCellDeps(scriptInfo.cellDeps.map((dep) => dep.cellDep));
4822
+ yield tx.completeInputsByUdt(signer, udtType);
4823
+ const inputsUdtBalance = yield tx.getInputsUdtBalance(this.client, udtType);
4824
+ const outputsUdtBalance = tx.getOutputsUdtBalance(udtType);
4825
+ const changeAmount = inputsUdtBalance - outputsUdtBalance;
4826
+ if (changeAmount > BigInt(0)) {
4827
+ const from = yield signer.getAddressObjSecp256k1();
4828
+ tx.outputs.push(core_1.ccc.CellOutput.from({
4829
+ lock: from.script,
4830
+ type: udtType,
4831
+ capacity: core_1.ccc.fixedPointFrom(0),
4832
+ }, core_1.ccc.hexFrom(core_1.ccc.numToBytes(changeAmount, 16))));
4833
+ tx.outputsData.push(core_1.ccc.hexFrom(core_1.ccc.numToBytes(changeAmount, 16)));
4834
+ }
4835
+ yield tx.completeFeeBy(signer, this.feeRate);
4836
+ const txHash = yield signer.sendTransaction(tx);
4837
+ return txHash;
4838
+ });
4839
+ }
4840
+ udtIssue(_a) {
4841
+ return __awaiter(this, arguments, void 0, function* ({ privateKey, kind, amount, typeArgs, toAddress }) {
4842
+ const signer = this.buildSigner(privateKey);
4843
+ const signerAddress = yield signer.getAddressObjSecp256k1();
4844
+ const to = toAddress ? yield core_1.ccc.Address.fromString(toAddress, this.client) : signerAddress;
4845
+ const amountBigInt = (0, validator_1.validateUdtAmount)(amount);
4846
+ let resolvedTypeArgs;
4847
+ if (kind === 'sudt') {
4848
+ if (typeArgs) {
4849
+ logger_1.logger.warn('SUDT type args are derived from the issuer lock hash; --type-args is ignored');
4850
+ }
4851
+ const issuerLockHash = signerAddress.script.hash();
4852
+ resolvedTypeArgs = ('0x' + issuerLockHash.slice(2, 42));
4853
+ }
4854
+ else {
4855
+ if (typeArgs) {
4856
+ resolvedTypeArgs = (0, validator_1.validateUdtTypeArgs)(kind, typeArgs);
4857
+ }
4858
+ else {
4859
+ const issuerLockHash = signerAddress.script.hash();
4860
+ resolvedTypeArgs = issuerLockHash;
4861
+ }
4862
+ }
4863
+ const udtType = yield this.buildUdtTypeScript(kind, resolvedTypeArgs);
4864
+ const outputsData = [core_1.ccc.hexFrom(core_1.ccc.numToBytes(amountBigInt, 16))];
4865
+ const tx = core_1.ccc.Transaction.from({
4866
+ outputs: [
4867
+ {
4868
+ lock: to.script,
4869
+ type: udtType,
4870
+ capacity: core_1.ccc.fixedPointFrom(0),
4871
+ },
4872
+ ],
4873
+ outputsData,
4874
+ });
4875
+ const scriptInfo = yield this.getUdtScriptInfo(kind);
4876
+ tx.addCellDeps(scriptInfo.cellDeps.map((dep) => dep.cellDep));
4877
+ yield tx.completeInputsByCapacity(signer);
4878
+ yield tx.completeFeeBy(signer, this.feeRate);
4879
+ const txHash = yield signer.sendTransaction(tx);
4880
+ return txHash;
4881
+ });
4882
+ }
4883
+ udtDestroy(_a) {
4884
+ return __awaiter(this, arguments, void 0, function* ({ privateKey, kind, typeArgs, amount }, { maxInputCells = DEFAULT_UDT_DESTROY_MAX_INPUT_CELLS } = {}) {
4885
+ var _b, e_3, _c, _d;
4886
+ const signer = this.buildSigner(privateKey);
4887
+ const from = yield signer.getAddressObjSecp256k1();
4888
+ const validatedTypeArgs = (0, validator_1.validateUdtTypeArgs)(kind, typeArgs);
4889
+ const udtType = yield this.buildUdtTypeScript(kind, validatedTypeArgs);
4890
+ const destroyAmount = (0, validator_1.validateUdtAmount)(amount);
4891
+ const cells = [];
4892
+ let totalBalance = BigInt(0);
4893
+ try {
4894
+ for (var _e = true, _f = __asyncValues(this.client.findCellsByLock(from.script, udtType, true)), _g; _g = yield _f.next(), _b = _g.done, !_b; _e = true) {
4895
+ _d = _g.value;
4896
+ _e = false;
4897
+ const cell = _d;
4898
+ if (cells.length >= maxInputCells) {
4899
+ throw new Error(`Too many UDT cells to destroy (limit: ${maxInputCells}); split into smaller operations`);
4900
+ }
4901
+ const cellBalance = readUdtBalance(cell.outputData);
4902
+ if (cellBalance == null) {
4903
+ continue;
4904
+ }
4905
+ cells.push(cell);
4906
+ totalBalance += cellBalance;
4907
+ }
4908
+ }
4909
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
4910
+ finally {
4911
+ try {
4912
+ if (!_e && !_b && (_c = _f.return)) yield _c.call(_f);
4913
+ }
4914
+ finally { if (e_3) throw e_3.error; }
4915
+ }
4916
+ if (totalBalance < destroyAmount) {
4917
+ throw new Error(`Insufficient UDT balance: ${totalBalance} < ${destroyAmount}`);
4918
+ }
4919
+ if (destroyAmount === totalBalance) {
4920
+ throw new Error('Destroying the entire UDT balance may be rejected by the UDT script. Leave at least 1 token or use a smaller amount.');
4921
+ }
4922
+ const tx = core_1.ccc.Transaction.from({});
4923
+ for (const cell of cells) {
4924
+ tx.addInput({ previousOutput: cell.outPoint });
4925
+ }
4926
+ const remaining = totalBalance - destroyAmount;
4927
+ tx.addOutput(core_1.ccc.CellOutput.from({
4928
+ lock: from.script,
4929
+ type: udtType,
4930
+ capacity: core_1.ccc.fixedPointFrom(0),
4931
+ }, core_1.ccc.hexFrom(core_1.ccc.numToBytes(remaining, 16))), core_1.ccc.hexFrom(core_1.ccc.numToBytes(remaining, 16)));
4932
+ const scriptInfo = yield this.getUdtScriptInfo(kind);
4933
+ tx.addCellDeps(scriptInfo.cellDeps.map((dep) => dep.cellDep));
4934
+ yield tx.completeInputsByCapacity(signer);
4935
+ yield tx.completeFeeBy(signer, this.feeRate);
4936
+ const txHash = yield signer.sendTransaction(tx);
4937
+ return txHash;
4938
+ });
4939
+ }
3975
4940
  deployScript(scriptBinBytes, privateKey) {
3976
4941
  return __awaiter(this, void 0, void 0, function* () {
3977
4942
  const signer = this.buildSigner(privateKey);
@@ -5103,222 +6068,530 @@ var __importStar = (this && this.__importStar) || (function () {
5103
6068
  return result;
5104
6069
  };
5105
6070
  })();
5106
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5107
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5108
- return new (P || (P = Promise))(function (resolve, reject) {
5109
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5110
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
5111
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
5112
- step((generator = generator.apply(thisArg, _arguments || [])).next());
5113
- });
6071
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6072
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6073
+ return new (P || (P = Promise))(function (resolve, reject) {
6074
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6075
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6076
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
6077
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
6078
+ });
6079
+ };
6080
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
6081
+ exports.CKBDebugger = void 0;
6082
+ const child_process_1 = __nccwpck_require__(35317);
6083
+ const path = __importStar(__nccwpck_require__(16928));
6084
+ const setting_1 = __nccwpck_require__(25546);
6085
+ const ckb_debugger_wasm_1 = __nccwpck_require__(52948);
6086
+ const logger_1 = __nccwpck_require__(65370);
6087
+ class CKBDebugger {
6088
+ static getWasmDebugger() {
6089
+ if (!this.wasmDebugger) {
6090
+ const wasmPath = path.join(__dirname, 'ckb-debugger.wasm');
6091
+ this.wasmDebugger = new ckb_debugger_wasm_1.CkbDebuggerWasi({
6092
+ wasmPath,
6093
+ captureOutput: false, // Use stdio directly since custom capture doesn't work with WASI
6094
+ });
6095
+ }
6096
+ return this.wasmDebugger;
6097
+ }
6098
+ /**
6099
+ * Check if we're in a recursive call to avoid infinite loops
6100
+ * This happens when ckb-debugger binary points to offckb CLI
6101
+ */
6102
+ static isRecursiveCall() {
6103
+ // Check if we're already running as a ckb-debugger process
6104
+ if (process.argv[1] && process.argv[1].includes('ckb-debugger')) {
6105
+ logger_1.logger.debug('Detected ckb-debugger process, using WASM to avoid recursion');
6106
+ return true;
6107
+ }
6108
+ // Check if we're running the debugger command (which could be called from ckb-debugger binary)
6109
+ if (process.argv.includes('debugger')) {
6110
+ logger_1.logger.debug('Detected debugger command, using WASM to avoid recursion');
6111
+ return true;
6112
+ }
6113
+ return false;
6114
+ }
6115
+ static shouldUseWasm() {
6116
+ if (this.isRecursiveCall()) {
6117
+ return true;
6118
+ }
6119
+ if (this.isBinaryInstalled() && this.isBinaryVersionValid()) {
6120
+ logger_1.logger.debug('Using native ckb-debugger (better performance)');
6121
+ return false;
6122
+ }
6123
+ else {
6124
+ logger_1.logger.debug('Native ckb-debugger not available, falling back to WASM version');
6125
+ return true;
6126
+ }
6127
+ }
6128
+ static execute(args) {
6129
+ return __awaiter(this, void 0, void 0, function* () {
6130
+ if (this.shouldUseWasm()) {
6131
+ try {
6132
+ const result = yield this.getWasmDebugger().run(args);
6133
+ if (result.exitCode !== 0) {
6134
+ process.exit(result.exitCode);
6135
+ }
6136
+ }
6137
+ catch (error) {
6138
+ logger_1.logger.error('WASM debugger execution failed:', error);
6139
+ process.exit(1);
6140
+ }
6141
+ }
6142
+ else {
6143
+ const command = `ckb-debugger ${args.join(' ')}`;
6144
+ (0, child_process_1.execSync)(command, { stdio: 'inherit' });
6145
+ }
6146
+ });
6147
+ }
6148
+ static runRaw(options) {
6149
+ return __awaiter(this, void 0, void 0, function* () {
6150
+ const args = options.split(' ').filter((arg) => arg.trim());
6151
+ yield this.execute(args);
6152
+ });
6153
+ }
6154
+ static runTxCellScript(_a) {
6155
+ return __awaiter(this, arguments, void 0, function* ({ fullTxJsonFilePath, cellIndex, cellType, scriptGroupType }) {
6156
+ const args = [
6157
+ '--tx-file',
6158
+ fullTxJsonFilePath,
6159
+ '--cell-index',
6160
+ cellIndex.toString(),
6161
+ '--cell-type',
6162
+ cellType,
6163
+ '--script-group-type',
6164
+ scriptGroupType,
6165
+ ];
6166
+ yield this.execute(args);
6167
+ });
6168
+ }
6169
+ static isBinaryInstalled() {
6170
+ const result = (0, child_process_1.spawnSync)('ckb-debugger', ['--version'], { stdio: 'ignore' });
6171
+ return result.status === 0;
6172
+ }
6173
+ static isBinaryVersionValid() {
6174
+ const result = (0, child_process_1.spawnSync)('ckb-debugger', ['--version']);
6175
+ if (result.status !== 0) {
6176
+ return false;
6177
+ }
6178
+ try {
6179
+ const version = result.stdout.toString().split(' ')[1];
6180
+ const settings = (0, setting_1.readSettings)();
6181
+ if (version < settings.tools.ckbDebugger.minVersion) {
6182
+ return false;
6183
+ }
6184
+ return true;
6185
+ }
6186
+ catch (error) {
6187
+ return false;
6188
+ }
6189
+ }
6190
+ static installCKBDebuggerBinary() {
6191
+ const command = `cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger`;
6192
+ try {
6193
+ logger_1.logger.info('Installing ckb-debugger...');
6194
+ (0, child_process_1.execSync)(command, { stdio: 'inherit' });
6195
+ logger_1.logger.info('ckb-debugger installed successfully. You can uninstall it by running: cargo uninstall ckb-debugger');
6196
+ }
6197
+ catch (error) {
6198
+ logger_1.logger.error('Failed to install ckb-debugger:', error);
6199
+ process.exit(1);
6200
+ }
6201
+ }
6202
+ /**
6203
+ * Create a ckb-debugger fallback binary that points to offckb debugger
6204
+ * This creates a shell script that calls: offckb debugger [args]
6205
+ * Purpose: Reduce user friction by providing a placeholder when native binary is not available
6206
+ * Users can install the real ckb-debugger binary for better performance if needed
6207
+ */
6208
+ static createCkbDebuggerFallback() {
6209
+ const fs = __nccwpck_require__(79896);
6210
+ const { spawnSync } = __nccwpck_require__(35317);
6211
+ const isWindows = process.platform === 'win32';
6212
+ const binName = isWindows ? 'ckb-debugger.cmd' : 'ckb-debugger';
6213
+ // Find the offckb binary location
6214
+ let offckbPath;
6215
+ if (isWindows) {
6216
+ const result = spawnSync('where', ['offckb'], { encoding: 'utf8' });
6217
+ offckbPath = result.stdout.trim().split('\n')[0];
6218
+ }
6219
+ else {
6220
+ const result = spawnSync('which', ['offckb'], { encoding: 'utf8' });
6221
+ offckbPath = result.stdout.trim();
6222
+ }
6223
+ if (!offckbPath) {
6224
+ logger_1.logger.error('❌ Could not find offckb binary. Please ensure offckb is installed and in your PATH.');
6225
+ process.exit(1);
6226
+ }
6227
+ // Get the directory where offckb is located
6228
+ const offckbDir = path.dirname(offckbPath);
6229
+ const targetPath = path.join(offckbDir, binName);
6230
+ // Create the binary content
6231
+ let binContent;
6232
+ if (isWindows) {
6233
+ // Windows batch file
6234
+ binContent = `@echo off
6235
+ offckb debugger %*`;
6236
+ }
6237
+ else {
6238
+ // Unix shell script
6239
+ binContent = `#!/bin/sh
6240
+ exec offckb debugger "$@"`;
6241
+ }
6242
+ try {
6243
+ // Ensure directory exists
6244
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
6245
+ // Write the binary
6246
+ fs.writeFileSync(targetPath, binContent);
6247
+ // Make executable on Unix systems
6248
+ if (!isWindows) {
6249
+ fs.chmodSync(targetPath, '755');
6250
+ }
6251
+ logger_1.logger.info(`✅ Created ckb-debugger fallback at: ${targetPath}`);
6252
+ logger_1.logger.info(` This fallback uses WASM and calls: offckb debugger [args]`);
6253
+ logger_1.logger.info(` For better performance, install the real binary: cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger`);
6254
+ logger_1.logger.info(` To uninstall the fallback binary: rm ${targetPath}`);
6255
+ }
6256
+ catch (error) {
6257
+ logger_1.logger.error(`❌ Failed to create ckb-debugger fallback: ${error.message}`);
6258
+ logger_1.logger.error(` Make sure you have write permissions to: ${path.dirname(targetPath)}`);
6259
+ process.exit(1);
6260
+ }
6261
+ }
6262
+ // Additional convenience methods that work with both native binary CLI and WASM
6263
+ static runWithArgs(args) {
6264
+ return __awaiter(this, void 0, void 0, function* () {
6265
+ yield this.execute(args);
6266
+ });
6267
+ }
6268
+ static version() {
6269
+ return __awaiter(this, void 0, void 0, function* () {
6270
+ if (this.shouldUseWasm()) {
6271
+ const result = yield this.getWasmDebugger().run(['--version']);
6272
+ return result;
6273
+ }
6274
+ else {
6275
+ const result = (0, child_process_1.spawnSync)('ckb-debugger', ['--version'], { encoding: 'utf8' });
6276
+ return {
6277
+ exitCode: result.status || 0,
6278
+ output: result.stdout,
6279
+ error: result.stderr,
6280
+ };
6281
+ }
6282
+ });
6283
+ }
6284
+ }
6285
+ exports.CKBDebugger = CKBDebugger;
6286
+ CKBDebugger.wasmDebugger = null;
6287
+
6288
+
6289
+ /***/ }),
6290
+
6291
+ /***/ 7020:
6292
+ /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
6293
+
6294
+ "use strict";
6295
+
6296
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6297
+ if (k2 === undefined) k2 = k;
6298
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6299
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6300
+ desc = { enumerable: true, get: function() { return m[k]; } };
6301
+ }
6302
+ Object.defineProperty(o, k2, desc);
6303
+ }) : (function(o, m, k, k2) {
6304
+ if (k2 === undefined) k2 = k;
6305
+ o[k2] = m[k];
6306
+ }));
6307
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
6308
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
6309
+ }) : function(o, v) {
6310
+ o["default"] = v;
6311
+ });
6312
+ var __importStar = (this && this.__importStar) || (function () {
6313
+ var ownKeys = function(o) {
6314
+ ownKeys = Object.getOwnPropertyNames || function (o) {
6315
+ var ar = [];
6316
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
6317
+ return ar;
6318
+ };
6319
+ return ownKeys(o);
6320
+ };
6321
+ return function (mod) {
6322
+ if (mod && mod.__esModule) return mod;
6323
+ var result = {};
6324
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
6325
+ __setModuleDefault(result, mod);
6326
+ return result;
6327
+ };
6328
+ })();
6329
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6330
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5114
6331
  };
5115
6332
  Object.defineProperty(exports, "__esModule", ({ value: true }));
5116
- exports.CKBDebugger = void 0;
6333
+ exports.CKBTui = void 0;
5117
6334
  const child_process_1 = __nccwpck_require__(35317);
5118
6335
  const path = __importStar(__nccwpck_require__(16928));
6336
+ const fs = __importStar(__nccwpck_require__(79896));
6337
+ const os = __importStar(__nccwpck_require__(70857));
6338
+ const crypto = __importStar(__nccwpck_require__(76982));
6339
+ const adm_zip_1 = __importDefault(__nccwpck_require__(83746));
5119
6340
  const setting_1 = __nccwpck_require__(25546);
5120
- const ckb_debugger_wasm_1 = __nccwpck_require__(52948);
5121
6341
  const logger_1 = __nccwpck_require__(65370);
5122
- class CKBDebugger {
5123
- static getWasmDebugger() {
5124
- if (!this.wasmDebugger) {
5125
- const wasmPath = path.join(__dirname, 'ckb-debugger.wasm');
5126
- this.wasmDebugger = new ckb_debugger_wasm_1.CkbDebuggerWasi({
5127
- wasmPath,
5128
- captureOutput: false, // Use stdio directly since custom capture doesn't work with WASI
5129
- });
6342
+ const fs_1 = __nccwpck_require__(37293);
6343
+ const DOWNLOAD_TIMEOUT_MS = 120000;
6344
+ const EXTRACT_TIMEOUT_MS = 60000;
6345
+ // Strict semver regex: v<major>.<minor>.<patch> (no leading zeros on digits)
6346
+ const STRICT_VERSION_REGEX = /^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
6347
+ class CKBTui {
6348
+ /**
6349
+ * Pure lookup — returns the expected binary path without triggering any
6350
+ * download or installation side effects. May return null if not yet computed.
6351
+ */
6352
+ static getBinaryPath() {
6353
+ if (!this.binaryPath) {
6354
+ const settings = (0, setting_1.readSettings)();
6355
+ const binDir = this.resolveAndValidateBinDir(settings.tools.rootFolder);
6356
+ const binaryName = process.platform === 'win32' ? 'ckb-tui.exe' : 'ckb-tui';
6357
+ this.binaryPath = path.join(binDir, binaryName);
5130
6358
  }
5131
- return this.wasmDebugger;
6359
+ return this.binaryPath;
5132
6360
  }
5133
6361
  /**
5134
- * Check if we're in a recursive call to avoid infinite loops
5135
- * This happens when ckb-debugger binary points to offckb CLI
6362
+ * Returns the binary path, downloading and installing if the binary
6363
+ * does not already exist.
5136
6364
  */
5137
- static isRecursiveCall() {
5138
- // Check if we're already running as a ckb-debugger process
5139
- if (process.argv[1] && process.argv[1].includes('ckb-debugger')) {
5140
- logger_1.logger.debug('Detected ckb-debugger process, using WASM to avoid recursion');
5141
- return true;
6365
+ static ensureInstalled() {
6366
+ const binaryPath = this.getBinaryPath();
6367
+ if (binaryPath && fs.existsSync(binaryPath)) {
6368
+ return binaryPath;
5142
6369
  }
5143
- // Check if we're running the debugger command (which could be called from ckb-debugger binary)
5144
- if (process.argv.includes('debugger')) {
5145
- logger_1.logger.debug('Detected debugger command, using WASM to avoid recursion');
5146
- return true;
5147
- }
5148
- return false;
6370
+ // Reset and re-install
6371
+ this.binaryPath = null;
6372
+ this.installSync();
6373
+ return this.binaryPath;
5149
6374
  }
5150
- static shouldUseWasm() {
5151
- if (this.isRecursiveCall()) {
5152
- return true;
6375
+ static isInstalled() {
6376
+ try {
6377
+ const binPath = this.getBinaryPath();
6378
+ return binPath !== null && fs.existsSync(binPath);
5153
6379
  }
5154
- if (this.isBinaryInstalled() && this.isBinaryVersionValid()) {
5155
- logger_1.logger.debug('Using native ckb-debugger (better performance)');
6380
+ catch (_a) {
5156
6381
  return false;
5157
6382
  }
5158
- else {
5159
- logger_1.logger.debug('Native ckb-debugger not available, falling back to WASM version');
5160
- return true;
5161
- }
5162
- }
5163
- static execute(args) {
5164
- return __awaiter(this, void 0, void 0, function* () {
5165
- if (this.shouldUseWasm()) {
5166
- try {
5167
- const result = yield this.getWasmDebugger().run(args);
5168
- if (result.exitCode !== 0) {
5169
- process.exit(result.exitCode);
5170
- }
5171
- }
5172
- catch (error) {
5173
- logger_1.logger.error('WASM debugger execution failed:', error);
5174
- process.exit(1);
5175
- }
5176
- }
5177
- else {
5178
- const command = `ckb-debugger ${args.join(' ')}`;
5179
- (0, child_process_1.execSync)(command, { stdio: 'inherit' });
5180
- }
5181
- });
5182
6383
  }
5183
- static runRaw(options) {
5184
- return __awaiter(this, void 0, void 0, function* () {
5185
- const args = options.split(' ').filter((arg) => arg.trim());
5186
- yield this.execute(args);
5187
- });
6384
+ static run(args = []) {
6385
+ const binaryPath = this.ensureInstalled();
6386
+ return (0, child_process_1.spawnSync)(binaryPath, args, { stdio: 'inherit' });
5188
6387
  }
5189
- static runTxCellScript(_a) {
5190
- return __awaiter(this, arguments, void 0, function* ({ fullTxJsonFilePath, cellIndex, cellType, scriptGroupType }) {
5191
- const args = [
5192
- '--tx-file',
5193
- fullTxJsonFilePath,
5194
- '--cell-index',
5195
- cellIndex.toString(),
5196
- '--cell-type',
5197
- cellType,
5198
- '--script-group-type',
5199
- scriptGroupType,
5200
- ];
5201
- yield this.execute(args);
5202
- });
6388
+ // --- private helpers ---
6389
+ /**
6390
+ * Resolve and validate that the configured rootFolder is under the
6391
+ * OffCKB data directory. Rejects paths that resolve outside.
6392
+ */
6393
+ static resolveAndValidateBinDir(configuredRoot) {
6394
+ const resolved = path.resolve(configuredRoot);
6395
+ const resolvedData = path.resolve(setting_1.dataPath);
6396
+ // Require the resolved path to be within the resolved data directory
6397
+ const relative = path.relative(resolvedData, resolved);
6398
+ if (relative.startsWith('..') || path.isAbsolute(relative)) {
6399
+ throw new Error(`tools.rootFolder ("${configuredRoot}") resolves outside the OffCKB data directory ` +
6400
+ `("${resolvedData}"). For security, tool binaries must be stored under the data path.`);
6401
+ }
6402
+ return resolved;
5203
6403
  }
5204
- static isBinaryInstalled() {
5205
- const result = (0, child_process_1.spawnSync)('ckb-debugger', ['--version'], { stdio: 'ignore' });
5206
- return result.status === 0;
6404
+ static validateVersion(version) {
6405
+ if (!STRICT_VERSION_REGEX.test(version)) {
6406
+ throw new Error(`Invalid version format: "${version}". Expected format: vX.Y.Z (e.g., v0.1.3)`);
6407
+ }
5207
6408
  }
5208
- static isBinaryVersionValid() {
5209
- const result = (0, child_process_1.spawnSync)('ckb-debugger', ['--version']);
5210
- if (result.status !== 0) {
5211
- return false;
6409
+ static getAssetName() {
6410
+ const platform = process.platform;
6411
+ const arch = process.arch;
6412
+ if (platform === 'darwin') {
6413
+ if (arch !== 'arm64') {
6414
+ throw new Error(`Unsupported architecture for macOS: ${arch}. Only Apple Silicon (arm64) is supported.`);
6415
+ }
6416
+ return 'ckb-tui-with-node-macos-aarch64.tar.gz';
5212
6417
  }
5213
- try {
5214
- const version = result.stdout.toString().split(' ')[1];
5215
- const settings = (0, setting_1.readSettings)();
5216
- if (version < settings.tools.ckbDebugger.minVersion) {
5217
- return false;
6418
+ else if (platform === 'linux') {
6419
+ if (arch !== 'x64') {
6420
+ throw new Error(`Unsupported architecture for Linux: ${arch}. Only x86_64 is supported.`);
5218
6421
  }
5219
- return true;
6422
+ return 'ckb-tui-with-node-linux-amd64.tar.gz';
5220
6423
  }
5221
- catch (error) {
5222
- return false;
6424
+ else if (platform === 'win32') {
6425
+ if (arch !== 'x64') {
6426
+ throw new Error(`Unsupported architecture for Windows: ${arch}. Only x86_64 is supported.`);
6427
+ }
6428
+ return 'ckb-tui-with-node-windows-amd64.zip';
5223
6429
  }
6430
+ throw new Error(`Unsupported platform: ${platform}`);
5224
6431
  }
5225
- static installCKBDebuggerBinary() {
5226
- const command = `cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger`;
6432
+ /**
6433
+ * Synchronously download and install the ckb-tui binary.
6434
+ * Uses spawnSync with array arguments (no shell interpolation) for security.
6435
+ */
6436
+ static installSync() {
6437
+ const settings = (0, setting_1.readSettings)();
6438
+ const version = settings.tools.ckbTui.version;
6439
+ this.validateVersion(version);
6440
+ const assetName = this.getAssetName();
6441
+ const binDir = this.resolveAndValidateBinDir(settings.tools.rootFolder);
6442
+ const binaryName = process.platform === 'win32' ? 'ckb-tui.exe' : 'ckb-tui';
6443
+ this.binaryPath = path.join(binDir, binaryName);
6444
+ const downloadUrl = `https://github.com/Officeyutong/ckb-tui/releases/download/${version}/${assetName}`;
6445
+ // Ensure the target directory exists
6446
+ fs.mkdirSync(binDir, { recursive: true });
6447
+ // Use a temp directory for atomic download & extraction
6448
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'offckb-ckb-tui-'));
6449
+ const archivePath = path.join(tempDir, assetName);
5227
6450
  try {
5228
- logger_1.logger.info('Installing ckb-debugger...');
5229
- (0, child_process_1.execSync)(command, { stdio: 'inherit' });
5230
- logger_1.logger.info('ckb-debugger installed successfully. You can uninstall it by running: cargo uninstall ckb-debugger');
6451
+ // 1. Download
6452
+ logger_1.logger.info(`Downloading ckb-tui from ${downloadUrl}...`);
6453
+ const curlResult = (0, child_process_1.spawnSync)('curl', ['-fsSL', '--max-time', '300', '-o', archivePath, downloadUrl], {
6454
+ stdio: 'inherit',
6455
+ timeout: DOWNLOAD_TIMEOUT_MS,
6456
+ });
6457
+ if (curlResult.error) {
6458
+ throw new Error(`Failed to download ckb-tui: ${curlResult.error.message}`);
6459
+ }
6460
+ if (curlResult.status !== 0) {
6461
+ throw new Error(`curl exited with code ${curlResult.status}`);
6462
+ }
6463
+ // 2. Verify checksum (best-effort: warns if checksum file is unavailable)
6464
+ this.verifyChecksum(version, assetName, archivePath);
6465
+ // 3. Extract to temp directory
6466
+ logger_1.logger.info('Extracting...');
6467
+ const extractDir = path.join(tempDir, 'extracted');
6468
+ fs.mkdirSync(extractDir, { recursive: true });
6469
+ this.extractArchive(archivePath, extractDir);
6470
+ // 4. Locate the extracted binary
6471
+ const extractedBinary = (0, fs_1.findFileInFolder)(extractDir, binaryName);
6472
+ if (!extractedBinary) {
6473
+ throw new Error(`ckb-tui binary ("${binaryName}") was not found after extraction.`);
6474
+ }
6475
+ // 5. Atomically move to the final location
6476
+ fs.renameSync(extractedBinary, this.binaryPath);
6477
+ // 6. Make executable on Unix
6478
+ if (process.platform !== 'win32') {
6479
+ fs.chmodSync(this.binaryPath, 0o755);
6480
+ }
6481
+ logger_1.logger.info('ckb-tui installed successfully.');
5231
6482
  }
5232
6483
  catch (error) {
5233
- logger_1.logger.error('Failed to install ckb-debugger:', error);
5234
- process.exit(1);
6484
+ // Reset cached path on failure so a subsequent call retries
6485
+ this.binaryPath = null;
6486
+ const message = error instanceof Error ? error.message : String(error);
6487
+ logger_1.logger.error('Failed to download/install ckb-tui:', message, '\nPlease check your network connectivity, verify that the specified version exists in the releases, ' +
6488
+ 'and ensure you have sufficient file system permissions.');
6489
+ throw error;
6490
+ }
6491
+ finally {
6492
+ // Clean up the temp directory
6493
+ try {
6494
+ fs.rmSync(tempDir, { recursive: true, force: true });
6495
+ }
6496
+ catch (_a) {
6497
+ // Best-effort cleanup — temp dir will be cleaned by the OS eventually
6498
+ }
5235
6499
  }
5236
6500
  }
5237
6501
  /**
5238
- * Create a ckb-debugger fallback binary that points to offckb debugger
5239
- * This creates a shell script that calls: offckb debugger [args]
5240
- * Purpose: Reduce user friction by providing a placeholder when native binary is not available
5241
- * Users can install the real ckb-debugger binary for better performance if needed
6502
+ * Best-effort SHA-256 checksum verification.
6503
+ * Downloads the checksum file published alongside the release asset and
6504
+ * verifies the downloaded archive. Logs a warning (but does not fail) if
6505
+ * the checksum file is unavailable this maintains compatibility while
6506
+ * the upstream project adopts checksum publishing.
5242
6507
  */
5243
- static createCkbDebuggerFallback() {
5244
- const fs = __nccwpck_require__(79896);
5245
- const { spawnSync } = __nccwpck_require__(35317);
5246
- const isWindows = process.platform === 'win32';
5247
- const binName = isWindows ? 'ckb-debugger.cmd' : 'ckb-debugger';
5248
- // Find the offckb binary location
5249
- let offckbPath;
5250
- if (isWindows) {
5251
- const result = spawnSync('where', ['offckb'], { encoding: 'utf8' });
5252
- offckbPath = result.stdout.trim().split('\n')[0];
5253
- }
5254
- else {
5255
- const result = spawnSync('which', ['offckb'], { encoding: 'utf8' });
5256
- offckbPath = result.stdout.trim();
5257
- }
5258
- if (!offckbPath) {
5259
- logger_1.logger.error('❌ Could not find offckb binary. Please ensure offckb is installed and in your PATH.');
5260
- process.exit(1);
5261
- }
5262
- // Get the directory where offckb is located
5263
- const offckbDir = path.dirname(offckbPath);
5264
- const targetPath = path.join(offckbDir, binName);
5265
- // Create the binary content
5266
- let binContent;
5267
- if (isWindows) {
5268
- // Windows batch file
5269
- binContent = `@echo off
5270
- offckb debugger %*`;
5271
- }
5272
- else {
5273
- // Unix shell script
5274
- binContent = `#!/bin/sh
5275
- exec offckb debugger "$@"`;
6508
+ static verifyChecksum(version, assetName, archivePath) {
6509
+ const checksumUrl = `https://github.com/Officeyutong/ckb-tui/releases/download/${version}/checksums-sha256.txt`;
6510
+ const checksumPath = path.join(path.dirname(archivePath), 'checksums-sha256.txt');
6511
+ const fetchResult = (0, child_process_1.spawnSync)('curl', ['-fsSL', '--max-time', '30', '-o', checksumPath, checksumUrl], {
6512
+ stdio: 'pipe',
6513
+ timeout: 30000,
6514
+ });
6515
+ if (fetchResult.status !== 0) {
6516
+ logger_1.logger.warn(`SHA-256 checksum file not available for version ${version}. ` +
6517
+ 'Skipping integrity verification. Consider asking the upstream maintainer to publish checksum files.');
6518
+ return;
5276
6519
  }
5277
6520
  try {
5278
- // Ensure directory exists
5279
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
5280
- // Write the binary
5281
- fs.writeFileSync(targetPath, binContent);
5282
- // Make executable on Unix systems
5283
- if (!isWindows) {
5284
- fs.chmodSync(targetPath, '755');
6521
+ const checksumContent = fs.readFileSync(checksumPath, 'utf8');
6522
+ const expectedHash = this.parseChecksumFile(checksumContent, assetName);
6523
+ if (!expectedHash) {
6524
+ logger_1.logger.warn(`Checksum entry for "${assetName}" not found in checksums file. Skipping verification.`);
6525
+ return;
5285
6526
  }
5286
- logger_1.logger.info(`✅ Created ckb-debugger fallback at: ${targetPath}`);
5287
- logger_1.logger.info(` This fallback uses WASM and calls: offckb debugger [args]`);
5288
- logger_1.logger.info(` For better performance, install the real binary: cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger`);
5289
- logger_1.logger.info(` To uninstall the fallback binary: rm ${targetPath}`);
6527
+ const actualHash = crypto.createHash('sha256').update(fs.readFileSync(archivePath)).digest('hex');
6528
+ if (actualHash !== expectedHash) {
6529
+ throw new Error(`SHA-256 checksum mismatch for ${assetName}.\n` +
6530
+ `Expected: ${expectedHash}\nActual: ${actualHash}\n` +
6531
+ 'The downloaded file may be corrupted or tampered with.');
6532
+ }
6533
+ logger_1.logger.info('SHA-256 checksum verified successfully.');
5290
6534
  }
5291
- catch (error) {
5292
- logger_1.logger.error(`❌ Failed to create ckb-debugger fallback: ${error.message}`);
5293
- logger_1.logger.error(` Make sure you have write permissions to: ${path.dirname(targetPath)}`);
5294
- process.exit(1);
6535
+ finally {
6536
+ try {
6537
+ fs.unlinkSync(checksumPath);
6538
+ }
6539
+ catch (_a) {
6540
+ // Best effort
6541
+ }
5295
6542
  }
5296
6543
  }
5297
- // Additional convenience methods that work with both native binary CLI and WASM
5298
- static runWithArgs(args) {
5299
- return __awaiter(this, void 0, void 0, function* () {
5300
- yield this.execute(args);
5301
- });
6544
+ /**
6545
+ * Parse a standard SHA-256 checksum file (format: "<hash> <filename>" per line)
6546
+ * and return the hex hash for the given asset name, or null if not found.
6547
+ */
6548
+ static parseChecksumFile(content, assetName) {
6549
+ for (const line of content.split('\n')) {
6550
+ const trimmed = line.trim();
6551
+ if (!trimmed || trimmed.startsWith('#'))
6552
+ continue;
6553
+ const match = trimmed.match(/^([0-9a-fA-F]{64})\s+[*]?(.+)$/);
6554
+ if (match && match[2] === assetName) {
6555
+ return match[1].toLowerCase();
6556
+ }
6557
+ }
6558
+ return null;
5302
6559
  }
5303
- static version() {
5304
- return __awaiter(this, void 0, void 0, function* () {
5305
- if (this.shouldUseWasm()) {
5306
- const result = yield this.getWasmDebugger().run(['--version']);
5307
- return result;
6560
+ /**
6561
+ * Extract a downloaded archive to the given directory.
6562
+ * Uses AdmZip for .zip files (Node-native, no shell) and spawnSync with array
6563
+ * arguments for .tar.gz (no shell interpolation).
6564
+ */
6565
+ static extractArchive(archivePath, extractDir) {
6566
+ if (archivePath.endsWith('.tar.gz')) {
6567
+ const result = (0, child_process_1.spawnSync)('tar', ['-xzf', archivePath, '-C', extractDir], {
6568
+ stdio: 'inherit',
6569
+ timeout: EXTRACT_TIMEOUT_MS,
6570
+ });
6571
+ if (result.error) {
6572
+ throw new Error(`tar extraction failed: ${result.error.message}`);
5308
6573
  }
5309
- else {
5310
- const result = (0, child_process_1.spawnSync)('ckb-debugger', ['--version'], { encoding: 'utf8' });
5311
- return {
5312
- exitCode: result.status || 0,
5313
- output: result.stdout,
5314
- error: result.stderr,
5315
- };
6574
+ if (result.status !== 0) {
6575
+ throw new Error(`tar exited with code ${result.status}`);
5316
6576
  }
5317
- });
6577
+ }
6578
+ else if (archivePath.endsWith('.zip')) {
6579
+ try {
6580
+ const zip = new adm_zip_1.default(archivePath);
6581
+ zip.extractAllTo(extractDir, true);
6582
+ }
6583
+ catch (error) {
6584
+ const message = error instanceof Error ? error.message : String(error);
6585
+ throw new Error(`ZIP extraction failed: ${message}`);
6586
+ }
6587
+ }
6588
+ else {
6589
+ throw new Error(`Unsupported archive format: ${path.extname(archivePath)}`);
6590
+ }
5318
6591
  }
5319
6592
  }
5320
- exports.CKBDebugger = CKBDebugger;
5321
- CKBDebugger.wasmDebugger = null;
6593
+ exports.CKBTui = CKBTui;
6594
+ CKBTui.binaryPath = null;
5322
6595
 
5323
6596
 
5324
6597
  /***/ }),
@@ -7749,15 +9022,25 @@ function getSubfolders(folderPath) {
7749
9022
  /***/ }),
7750
9023
 
7751
9024
  /***/ 27814:
7752
- /***/ ((__unused_webpack_module, exports) => {
9025
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
7753
9026
 
7754
9027
  "use strict";
7755
9028
 
7756
9029
  Object.defineProperty(exports, "__esModule", ({ value: true }));
7757
9030
  exports.buildTestnetTxLink = buildTestnetTxLink;
9031
+ exports.logTxSuccess = logTxSuccess;
9032
+ const logger_1 = __nccwpck_require__(65370);
7758
9033
  function buildTestnetTxLink(txHash) {
7759
9034
  return `https://pudge.explorer.nervos.org/transaction/${txHash}`;
7760
9035
  }
9036
+ function logTxSuccess(network, txHash, action) {
9037
+ if (network === 'testnet') {
9038
+ logger_1.logger.info(`Successfully ${action}, check ${buildTestnetTxLink(txHash)} for details.`);
9039
+ }
9040
+ else {
9041
+ logger_1.logger.info(`Successfully ${action}, txHash:`, txHash);
9042
+ }
9043
+ }
7761
9044
 
7762
9045
 
7763
9046
  /***/ }),
@@ -7819,6 +9102,7 @@ class UnifiedLogger {
7819
9102
  constructor(options = {}) {
7820
9103
  this.enableColors = options.enableColors !== false;
7821
9104
  this.showLevel = options.showLevel !== false;
9105
+ this.jsonMode = options.jsonMode === true;
7822
9106
  // Create Winston logger with custom format and levels
7823
9107
  this.logger = winston_1.default.createLogger({
7824
9108
  level: options.level || node_process_1.default.env.LOG_LEVEL || 'info',
@@ -7832,17 +9116,33 @@ class UnifiedLogger {
7832
9116
  format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.errors({ stack: true }), winston_1.default.format.printf(({ level, message, timestamp }) => {
7833
9117
  return this.formatMessage(level, message, timestamp);
7834
9118
  })),
7835
- transports: [
9119
+ transports: options.transports || [
7836
9120
  new winston_1.default.transports.Console({
7837
9121
  stderrLevels: ['error', 'warn'],
7838
9122
  }),
7839
9123
  ],
7840
9124
  });
7841
9125
  }
9126
+ /**
9127
+ * Toggle JSON output mode. When enabled, every log line is emitted as a
9128
+ * structured JSON object, which is easier for agents and scripts to parse.
9129
+ */
9130
+ setJsonMode(enabled) {
9131
+ this.jsonMode = enabled;
9132
+ }
7842
9133
  /**
7843
9134
  * Format the message with appropriate colors and structure
7844
9135
  */
7845
- formatMessage(level, message, _timestamp) {
9136
+ formatMessage(level, message, timestamp) {
9137
+ // Agent-friendly JSON output: one JSON object per log line
9138
+ if (this.jsonMode) {
9139
+ const normalizedMessage = Array.isArray(message) ? message.join('\n') : String(message);
9140
+ return JSON.stringify({
9141
+ level,
9142
+ message: normalizedMessage,
9143
+ timestamp,
9144
+ });
9145
+ }
7846
9146
  // If showLevel is false, return just the message
7847
9147
  if (!this.showLevel) {
7848
9148
  if (Array.isArray(message)) {
@@ -7925,6 +9225,12 @@ class UnifiedLogger {
7925
9225
  * Log a message with the specified level
7926
9226
  */
7927
9227
  log(level, message) {
9228
+ // In JSON mode, emit multi-line messages as a single structured log entry
9229
+ // so agents can parse one complete JSON object per line.
9230
+ if (this.jsonMode && Array.isArray(message)) {
9231
+ this.logger.log(level, message.join('\n'));
9232
+ return;
9233
+ }
7928
9234
  if (Array.isArray(message)) {
7929
9235
  message.forEach((line) => this.logger.log(level, line));
7930
9236
  }
@@ -8091,6 +9397,11 @@ exports.isValidNetworkString = isValidNetworkString;
8091
9397
  exports.validateNetworkOpt = validateNetworkOpt;
8092
9398
  exports.isValidVersion = isValidVersion;
8093
9399
  exports.normalizePrivKey = normalizePrivKey;
9400
+ exports.isValidUdtKind = isValidUdtKind;
9401
+ exports.validateUdtKind = validateUdtKind;
9402
+ exports.validateUdtAmount = validateUdtAmount;
9403
+ exports.validateHexString = validateHexString;
9404
+ exports.validateUdtTypeArgs = validateUdtTypeArgs;
8094
9405
  const path_1 = __importDefault(__nccwpck_require__(16928));
8095
9406
  const fs_1 = __importDefault(__nccwpck_require__(79896));
8096
9407
  const base_1 = __nccwpck_require__(69951);
@@ -8179,6 +9490,46 @@ function normalizePrivKey(privKey) {
8179
9490
  // Return the formally strictly padded ckb format `0x` string
8180
9491
  return '0x' + key;
8181
9492
  }
9493
+ function isValidUdtKind(kind) {
9494
+ return kind === 'sudt' || kind === 'xudt';
9495
+ }
9496
+ function validateUdtKind(kind) {
9497
+ if (!kind) {
9498
+ throw new Error('UDT kind is required');
9499
+ }
9500
+ if (!isValidUdtKind(kind)) {
9501
+ throw new Error(`invalid UDT kind "${kind}", must be "sudt" or "xudt"`);
9502
+ }
9503
+ }
9504
+ const U128_MAX = (BigInt(1) << BigInt(128)) - BigInt(1);
9505
+ function validateUdtAmount(amount) {
9506
+ if (!/^\d+$/.test(amount)) {
9507
+ throw new Error(`invalid UDT amount "${amount}", must be a non-negative decimal integer`);
9508
+ }
9509
+ const value = BigInt(amount);
9510
+ if (value > U128_MAX) {
9511
+ throw new Error(`UDT amount exceeds 128-bit max: ${amount}`);
9512
+ }
9513
+ return value;
9514
+ }
9515
+ const HEX_REGEX = /^0x[0-9a-fA-F]*$/;
9516
+ function validateHexString(value, name) {
9517
+ if (!value || !HEX_REGEX.test(value)) {
9518
+ throw new Error(`invalid ${name} "${value}", must be a hex string starting with 0x`);
9519
+ }
9520
+ return value;
9521
+ }
9522
+ function validateUdtTypeArgs(kind, typeArgs) {
9523
+ const hex = validateHexString(typeArgs, 'type args');
9524
+ const byteLength = (hex.length - 2) / 2;
9525
+ if (kind === 'sudt' && byteLength !== 20) {
9526
+ throw new Error(`invalid SUDT type args length: expected 20 bytes, got ${byteLength}`);
9527
+ }
9528
+ if (kind === 'xudt' && byteLength !== 32) {
9529
+ throw new Error(`invalid xUDT type args length: expected 32 bytes, got ${byteLength}`);
9530
+ }
9531
+ return hex;
9532
+ }
8182
9533
 
8183
9534
 
8184
9535
  /***/ }),
@@ -128150,7 +129501,7 @@ module.exports = {"version":"3.17.0"};
128150
129501
  /***/ ((module) => {
128151
129502
 
128152
129503
  "use strict";
128153
- module.exports = /*#__PURE__*/JSON.parse('{"rE":"0.4.8","h_":"ckb development network for your first try"}');
129504
+ module.exports = /*#__PURE__*/JSON.parse('{"rE":"0.4.9-canary-2b6b3af.0","h_":"ckb development network for your first try"}');
128154
129505
 
128155
129506
  /***/ })
128156
129507