@fiber-pay/node 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.js +97 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { KeyConfig, KeyInfo } from '@fiber-pay/sdk';
|
|
|
5
5
|
* Shared constants for the @fiber-pay/node package
|
|
6
6
|
*/
|
|
7
7
|
/** Default Fiber Network Node binary version used for downloads when no version is specified. */
|
|
8
|
-
declare const DEFAULT_FIBER_VERSION = "v0.
|
|
8
|
+
declare const DEFAULT_FIBER_VERSION = "v0.8.0";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Binary Manager
|
|
@@ -135,6 +135,8 @@ interface MigrationCheckResult {
|
|
|
135
135
|
needed: boolean;
|
|
136
136
|
/** Whether the store is valid (parseable) */
|
|
137
137
|
valid: boolean;
|
|
138
|
+
/** Whether this fnn-migrate version does not support pre-check mode */
|
|
139
|
+
precheckUnsupported: boolean;
|
|
138
140
|
/** Human-readable status message */
|
|
139
141
|
message: string;
|
|
140
142
|
/** Path to the store that was checked */
|
|
@@ -166,12 +168,13 @@ interface MigrationOptions {
|
|
|
166
168
|
}
|
|
167
169
|
declare class MigrationManager {
|
|
168
170
|
private migrateBinaryPath;
|
|
171
|
+
private helpTextCache;
|
|
169
172
|
constructor(migrateBinaryPath: string);
|
|
170
173
|
/**
|
|
171
174
|
* Check whether the store needs migration or is incompatible.
|
|
172
175
|
*
|
|
173
|
-
* Runs `fnn-migrate
|
|
174
|
-
*
|
|
176
|
+
* Runs `fnn-migrate` compatibility check when supported by the installed
|
|
177
|
+
* migrate helper.
|
|
175
178
|
*/
|
|
176
179
|
check(storePath: string): Promise<MigrationCheckResult>;
|
|
177
180
|
/**
|
|
@@ -202,6 +205,11 @@ declare class MigrationManager {
|
|
|
202
205
|
*/
|
|
203
206
|
static storeExists(dataDir: string): boolean;
|
|
204
207
|
private ensureBinaryExists;
|
|
208
|
+
private getHelpText;
|
|
209
|
+
private resolveTargetArgCandidates;
|
|
210
|
+
private isArgShapeError;
|
|
211
|
+
private execWithStoreTargetArgs;
|
|
212
|
+
private execMigrateCommand;
|
|
205
213
|
private extractStderr;
|
|
206
214
|
}
|
|
207
215
|
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/constants.ts
|
|
2
|
-
var DEFAULT_FIBER_VERSION = "v0.
|
|
2
|
+
var DEFAULT_FIBER_VERSION = "v0.8.0";
|
|
3
3
|
|
|
4
4
|
// src/binary/manager.ts
|
|
5
5
|
import { exec } from "child_process";
|
|
@@ -434,6 +434,7 @@ import { promisify as promisify2 } from "util";
|
|
|
434
434
|
var execFileAsync = promisify2(execFile);
|
|
435
435
|
var MigrationManager = class _MigrationManager {
|
|
436
436
|
migrateBinaryPath;
|
|
437
|
+
helpTextCache = null;
|
|
437
438
|
constructor(migrateBinaryPath) {
|
|
438
439
|
this.migrateBinaryPath = migrateBinaryPath;
|
|
439
440
|
}
|
|
@@ -443,8 +444,8 @@ var MigrationManager = class _MigrationManager {
|
|
|
443
444
|
/**
|
|
444
445
|
* Check whether the store needs migration or is incompatible.
|
|
445
446
|
*
|
|
446
|
-
* Runs `fnn-migrate
|
|
447
|
-
*
|
|
447
|
+
* Runs `fnn-migrate` compatibility check when supported by the installed
|
|
448
|
+
* migrate helper.
|
|
448
449
|
*/
|
|
449
450
|
async check(storePath) {
|
|
450
451
|
this.ensureBinaryExists();
|
|
@@ -452,21 +453,33 @@ var MigrationManager = class _MigrationManager {
|
|
|
452
453
|
return {
|
|
453
454
|
needed: false,
|
|
454
455
|
valid: true,
|
|
456
|
+
precheckUnsupported: false,
|
|
455
457
|
message: "Store does not exist yet \u2014 no migration needed.",
|
|
456
458
|
storePath
|
|
457
459
|
};
|
|
458
460
|
}
|
|
461
|
+
const helpText = await this.getHelpText();
|
|
462
|
+
const supportsCheckValidate = helpText.includes("--check-validate");
|
|
463
|
+
if (!supportsCheckValidate) {
|
|
464
|
+
return {
|
|
465
|
+
needed: false,
|
|
466
|
+
valid: true,
|
|
467
|
+
precheckUnsupported: true,
|
|
468
|
+
message: "Store pre-check is not supported by this fnn-migrate version; skipping compatibility check.",
|
|
469
|
+
storePath
|
|
470
|
+
};
|
|
471
|
+
}
|
|
459
472
|
try {
|
|
460
|
-
const { stdout } = await
|
|
461
|
-
"-p",
|
|
462
|
-
storePath,
|
|
473
|
+
const { stdout, stderr } = await this.execWithStoreTargetArgs(storePath, [
|
|
463
474
|
"--check-validate"
|
|
464
475
|
]);
|
|
465
|
-
const output = stdout
|
|
476
|
+
const output = `${stdout}
|
|
477
|
+
${stderr}`.trim();
|
|
466
478
|
if (output.includes("validate success")) {
|
|
467
479
|
return {
|
|
468
480
|
needed: false,
|
|
469
481
|
valid: true,
|
|
482
|
+
precheckUnsupported: false,
|
|
470
483
|
message: "Store is up-to-date, no migration needed.",
|
|
471
484
|
storePath
|
|
472
485
|
};
|
|
@@ -474,6 +487,7 @@ var MigrationManager = class _MigrationManager {
|
|
|
474
487
|
return {
|
|
475
488
|
needed: false,
|
|
476
489
|
valid: true,
|
|
490
|
+
precheckUnsupported: false,
|
|
477
491
|
message: output || "Store validation passed.",
|
|
478
492
|
storePath
|
|
479
493
|
};
|
|
@@ -486,6 +500,7 @@ var MigrationManager = class _MigrationManager {
|
|
|
486
500
|
return {
|
|
487
501
|
needed: true,
|
|
488
502
|
valid: false,
|
|
503
|
+
precheckUnsupported: false,
|
|
489
504
|
message: "Store requires a breaking migration that cannot be auto-migrated. You need to:\n 1. Start the OLD version of fnn\n 2. Close all channels (cooperative or forced)\n 3. Stop the old node\n 4. Remove the store directory\n 5. Start the new fnn version with a fresh database\n\nSee: https://github.com/nervosnetwork/fiber/wiki/Fiber-Breaking-Change-Migration-Guide",
|
|
490
505
|
storePath
|
|
491
506
|
};
|
|
@@ -494,6 +509,7 @@ var MigrationManager = class _MigrationManager {
|
|
|
494
509
|
return {
|
|
495
510
|
needed: true,
|
|
496
511
|
valid: true,
|
|
512
|
+
precheckUnsupported: false,
|
|
497
513
|
message: "Store needs migration. Run `fiber-pay node upgrade` to migrate.",
|
|
498
514
|
storePath
|
|
499
515
|
};
|
|
@@ -502,6 +518,7 @@ var MigrationManager = class _MigrationManager {
|
|
|
502
518
|
return {
|
|
503
519
|
needed: true,
|
|
504
520
|
valid: false,
|
|
521
|
+
precheckUnsupported: false,
|
|
505
522
|
message: `Store is incompatible: ${stderr}`,
|
|
506
523
|
storePath
|
|
507
524
|
};
|
|
@@ -509,6 +526,7 @@ var MigrationManager = class _MigrationManager {
|
|
|
509
526
|
return {
|
|
510
527
|
needed: true,
|
|
511
528
|
valid: false,
|
|
529
|
+
precheckUnsupported: false,
|
|
512
530
|
message: `Store validation failed: ${stderr}`,
|
|
513
531
|
storePath
|
|
514
532
|
};
|
|
@@ -547,7 +565,8 @@ var MigrationManager = class _MigrationManager {
|
|
|
547
565
|
};
|
|
548
566
|
}
|
|
549
567
|
const checkResult = await this.check(storePath);
|
|
550
|
-
|
|
568
|
+
const precheckUnsupported = checkResult.precheckUnsupported;
|
|
569
|
+
if (!checkResult.needed && !(force && precheckUnsupported)) {
|
|
551
570
|
return {
|
|
552
571
|
success: true,
|
|
553
572
|
message: checkResult.message
|
|
@@ -572,11 +591,7 @@ var MigrationManager = class _MigrationManager {
|
|
|
572
591
|
}
|
|
573
592
|
}
|
|
574
593
|
try {
|
|
575
|
-
const { stdout, stderr } = await
|
|
576
|
-
"-p",
|
|
577
|
-
storePath,
|
|
578
|
-
"--skip-confirm"
|
|
579
|
-
]);
|
|
594
|
+
const { stdout, stderr } = await this.execMigrateCommand(storePath);
|
|
580
595
|
const output = `${stdout}
|
|
581
596
|
${stderr}`.trim();
|
|
582
597
|
if (output.includes("migrated successfully") || output.includes("db migrated")) {
|
|
@@ -587,6 +602,14 @@ ${stderr}`.trim();
|
|
|
587
602
|
output
|
|
588
603
|
};
|
|
589
604
|
}
|
|
605
|
+
if (output.toLowerCase().includes("no need to migrate")) {
|
|
606
|
+
return {
|
|
607
|
+
success: true,
|
|
608
|
+
backupPath,
|
|
609
|
+
message: "Store is already up-to-date; no migration needed.",
|
|
610
|
+
output
|
|
611
|
+
};
|
|
612
|
+
}
|
|
590
613
|
let ambiguousMessage = `Migration command finished without errors, but the expected success message was not found. Output: ${output}`;
|
|
591
614
|
if (backupPath) {
|
|
592
615
|
ambiguousMessage += `
|
|
@@ -662,6 +685,67 @@ Re-download the Fiber binary with: fiber-pay binary download --force`
|
|
|
662
685
|
);
|
|
663
686
|
}
|
|
664
687
|
}
|
|
688
|
+
async getHelpText() {
|
|
689
|
+
if (this.helpTextCache !== null) {
|
|
690
|
+
return this.helpTextCache;
|
|
691
|
+
}
|
|
692
|
+
try {
|
|
693
|
+
const { stdout, stderr } = await execFileAsync(this.migrateBinaryPath, ["--help"]);
|
|
694
|
+
this.helpTextCache = `${stdout}
|
|
695
|
+
${stderr}`;
|
|
696
|
+
return this.helpTextCache;
|
|
697
|
+
} catch (error) {
|
|
698
|
+
this.helpTextCache = this.extractStderr(error);
|
|
699
|
+
return this.helpTextCache;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
async resolveTargetArgCandidates(storePath) {
|
|
703
|
+
const helpText = await this.getHelpText();
|
|
704
|
+
const fiberDataDir = dirname(storePath);
|
|
705
|
+
const prefersDirArg = helpText.includes("--dir");
|
|
706
|
+
if (prefersDirArg) {
|
|
707
|
+
return [
|
|
708
|
+
["--dir", fiberDataDir],
|
|
709
|
+
["-p", storePath]
|
|
710
|
+
];
|
|
711
|
+
}
|
|
712
|
+
return [
|
|
713
|
+
["-p", storePath],
|
|
714
|
+
["--dir", fiberDataDir]
|
|
715
|
+
];
|
|
716
|
+
}
|
|
717
|
+
isArgShapeError(message) {
|
|
718
|
+
const lower = message.toLowerCase();
|
|
719
|
+
return lower.includes("unexpected argument") || lower.includes("found argument") || lower.includes("unknown option") || lower.includes("invalid option") || lower.includes("usage: fnn-migrate");
|
|
720
|
+
}
|
|
721
|
+
async execWithStoreTargetArgs(storePath, extraArgs) {
|
|
722
|
+
const candidates = await this.resolveTargetArgCandidates(storePath);
|
|
723
|
+
let lastError = new Error("No valid fnn-migrate target argument style found.");
|
|
724
|
+
for (const targetArgs of candidates) {
|
|
725
|
+
try {
|
|
726
|
+
return await execFileAsync(this.migrateBinaryPath, [...targetArgs, ...extraArgs]);
|
|
727
|
+
} catch (error) {
|
|
728
|
+
const msg = this.extractStderr(error);
|
|
729
|
+
if (this.isArgShapeError(msg)) {
|
|
730
|
+
lastError = error;
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
throw error;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
throw lastError;
|
|
737
|
+
}
|
|
738
|
+
async execMigrateCommand(storePath) {
|
|
739
|
+
try {
|
|
740
|
+
return await this.execWithStoreTargetArgs(storePath, ["--skip-confirm"]);
|
|
741
|
+
} catch (error) {
|
|
742
|
+
const msg = this.extractStderr(error);
|
|
743
|
+
if (!this.isArgShapeError(msg) || !msg.includes("--skip-confirm")) {
|
|
744
|
+
throw error;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
return this.execWithStoreTargetArgs(storePath, ["-s"]);
|
|
748
|
+
}
|
|
665
749
|
extractStderr(error) {
|
|
666
750
|
if (error && typeof error === "object") {
|
|
667
751
|
const e = error;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/binary/manager.ts","../src/migration/manager.ts","../src/process/manager.ts","../src/process/yaml.ts","../src/security/key-manager.ts"],"sourcesContent":["/**\n * Shared constants for the @fiber-pay/node package\n */\n\n/** Default Fiber Network Node binary version used for downloads when no version is specified. */\nexport const DEFAULT_FIBER_VERSION = 'v0.7.1';\n","/**\n * Binary Manager\n * Handles downloading, installing, and managing the Fiber Network Node (fnn) binary\n */\n\nimport { exec } from 'node:child_process';\nimport { chmodSync, existsSync, mkdirSync, unlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { DEFAULT_FIBER_VERSION } from '../constants.js';\n\nconst execAsync = promisify(exec);\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type Platform = 'darwin' | 'linux' | 'win32';\nexport type Arch = 'x64' | 'arm64';\n\nexport interface BinaryInfo {\n /** Path to the binary */\n path: string;\n /** Version of the binary */\n version: string;\n /** Whether the binary exists and is executable */\n ready: boolean;\n}\n\nexport interface DownloadOptions {\n /** Target directory for the binary */\n installDir?: string;\n /** Specific version to download (default: latest) */\n version?: string;\n /** Force re-download even if binary exists */\n force?: boolean;\n /** Progress callback */\n onProgress?: (progress: DownloadProgress) => void;\n}\n\nexport interface DownloadProgress {\n phase: 'fetching' | 'downloading' | 'extracting' | 'installing';\n percent?: number;\n message: string;\n}\n\ninterface AssetCandidate {\n name: string;\n url: string;\n usesRosetta: boolean;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst GITHUB_REPO = 'nervosnetwork/fiber';\nconst GITHUB_RELEASES_URL = `https://github.com/${GITHUB_REPO}/releases`;\nconst DEFAULT_INSTALL_DIR = join(process.env.HOME || '~', '.fiber-pay', 'bin');\nconst RELEASE_TAG_PATTERN = /^v\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/;\n\n// Binary naming patterns for different platforms\n// Pattern used to match assets: fnn_vX.X.X-{pattern}.tar.gz\nconst BINARY_PATTERNS: Record<Platform, Record<Arch, string>> = {\n darwin: {\n x64: 'x86_64-darwin',\n arm64: 'aarch64-darwin', // May not exist yet, will fallback to x64\n },\n linux: {\n x64: 'x86_64-linux',\n arm64: 'aarch64-linux',\n },\n win32: {\n x64: 'x86_64-windows',\n arm64: 'aarch64-windows',\n },\n};\n\n// =============================================================================\n// Binary Manager\n// =============================================================================\n\nexport class BinaryManager {\n private installDir: string;\n\n constructor(installDir?: string) {\n this.installDir = installDir || DEFAULT_INSTALL_DIR;\n }\n\n /**\n * Get the current platform and architecture\n */\n getPlatformInfo(): { platform: Platform; arch: Arch } {\n const platform = process.platform as Platform;\n const arch = process.arch === 'arm64' ? 'arm64' : 'x64';\n\n if (!['darwin', 'linux', 'win32'].includes(platform)) {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n return { platform, arch };\n }\n\n /**\n * Get the pattern to match for the current platform\n */\n getAssetPattern(): string {\n const { platform, arch } = this.getPlatformInfo();\n const pattern = BINARY_PATTERNS[platform]?.[arch];\n\n if (!pattern) {\n throw new Error(`No binary pattern for ${platform}/${arch}`);\n }\n\n return pattern;\n }\n\n /**\n * Get the path where the binary should be installed\n */\n getBinaryPath(): string {\n const { platform } = this.getPlatformInfo();\n const binaryName = platform === 'win32' ? 'fnn.exe' : 'fnn';\n return join(this.installDir, binaryName);\n }\n\n /**\n * Get the path where the fnn-migrate binary should be installed\n */\n getMigrateBinaryPath(): string {\n const { platform } = this.getPlatformInfo();\n const binaryName = platform === 'win32' ? 'fnn-migrate.exe' : 'fnn-migrate';\n return join(this.installDir, binaryName);\n }\n\n /**\n * Check if the binary is installed and get its info\n */\n async getBinaryInfo(): Promise<BinaryInfo> {\n const binaryPath = this.getBinaryPath();\n const exists = existsSync(binaryPath);\n\n let version = 'unknown';\n let ready = false;\n\n if (exists) {\n try {\n const { stdout } = await execAsync(`\"${binaryPath}\" --version`);\n // Output format: \"fnn Fiber v0.7.1 (f761b6d 2026-01-14)\"\n // Extract the version number\n const versionMatch = stdout.match(/v(\\d+\\.\\d+\\.\\d+)/);\n version = versionMatch ? versionMatch[1] : stdout.trim();\n ready = true;\n } catch {\n // Binary exists but may not be executable\n ready = false;\n }\n }\n\n return { path: binaryPath, version, ready };\n }\n\n /**\n * Fetch the latest release tag from GitHub (no API, follows redirect)\n */\n async getLatestTag(): Promise<string> {\n const response = await fetch(`${GITHUB_RELEASES_URL}/latest`, {\n redirect: 'manual',\n headers: {\n 'User-Agent': 'fiber-pay',\n },\n });\n\n const location = response.headers.get('location') || response.url;\n if (!location) {\n throw new Error(`Failed to resolve latest release tag (status: ${response.status})`);\n }\n\n const match = location.match(/\\/tag\\/([^/?#]+)/);\n if (!match) {\n throw new Error(`Failed to parse release tag from redirect: ${location}`);\n }\n\n return match[1];\n }\n\n /**\n * Normalize a version into a release tag\n */\n normalizeTag(version: string): string {\n const input = version.trim();\n if (!input) {\n throw new Error('Version cannot be empty');\n }\n\n const tag = input.startsWith('v') ? input : `v${input}`;\n if (!RELEASE_TAG_PATTERN.test(tag)) {\n throw new Error(\n `Invalid version format: ${version}. Expected semver-like tag, e.g. v0.7.1 or v0.7.1-rc.1`,\n );\n }\n\n return tag;\n }\n\n /**\n * Build download candidates for the current platform\n */\n buildAssetCandidates(tag: string): AssetCandidate[] {\n const { platform, arch } = this.getPlatformInfo();\n const extensions = platform === 'win32' ? ['zip', 'tar.gz'] : ['tar.gz'];\n const variants = platform === 'win32' ? ['', '-portable'] : ['-portable', ''];\n const patterns: Array<{ pattern: string; usesRosetta: boolean }> = [\n { pattern: BINARY_PATTERNS[platform][arch], usesRosetta: false },\n ];\n\n if (platform === 'darwin' && arch === 'arm64') {\n patterns.push({ pattern: BINARY_PATTERNS.darwin.x64, usesRosetta: true });\n }\n\n const candidates: AssetCandidate[] = [];\n for (const { pattern, usesRosetta } of patterns) {\n for (const variant of variants) {\n for (const ext of extensions) {\n const name = `fnn_${tag}-${pattern}${variant}.${ext}`;\n const url = `${GITHUB_RELEASES_URL}/download/${tag}/${name}`;\n candidates.push({ name, url, usesRosetta });\n }\n }\n }\n\n return candidates;\n }\n\n /**\n * Validate Rosetta support when falling back to x86_64 binary on Apple Silicon.\n */\n private async ensureRosettaAvailable(): Promise<void> {\n const { platform, arch } = this.getPlatformInfo();\n if (platform !== 'darwin' || arch !== 'arm64') {\n return;\n }\n\n try {\n await execAsync('arch -x86_64 /usr/bin/true');\n } catch {\n throw new Error(\n 'Apple Silicon fallback selected x86_64 binary, but Rosetta 2 is not available. ' +\n 'Install Rosetta with: softwareupdate --install-rosetta --agree-to-license',\n );\n }\n }\n\n /**\n * Download and install the Fiber binary\n */\n async download(options: DownloadOptions = {}): Promise<BinaryInfo> {\n const { version, force = false, onProgress = () => {} } = options;\n\n const binaryPath = this.getBinaryPath();\n\n // Check if already installed\n if (!force && existsSync(binaryPath)) {\n const info = await this.getBinaryInfo();\n if (info.ready) {\n onProgress({ phase: 'installing', message: `Binary already installed at ${binaryPath}` });\n return info;\n }\n }\n\n // Ensure install directory exists\n if (!existsSync(this.installDir)) {\n mkdirSync(this.installDir, { recursive: true });\n }\n\n // Resolve release tag\n onProgress({ phase: 'fetching', message: 'Resolving release tag...' });\n const tag = this.normalizeTag(version || DEFAULT_FIBER_VERSION);\n\n onProgress({ phase: 'fetching', message: `Found release: ${tag}` });\n\n // Build asset candidates\n const candidates = this.buildAssetCandidates(tag);\n\n let response: Response | undefined;\n let selected: AssetCandidate | undefined;\n const attempted: string[] = [];\n\n for (const candidate of candidates) {\n onProgress({\n phase: 'downloading',\n message: `Downloading ${candidate.name} from ${candidate.url}...`,\n percent: 0,\n });\n attempted.push(candidate.name);\n const candidateResponse = await fetch(candidate.url, {\n headers: { 'User-Agent': 'fiber-pay' },\n });\n\n if (candidateResponse.ok) {\n response = candidateResponse;\n selected = candidate;\n break;\n }\n }\n\n if (!response || !selected) {\n const attemptedUrls = candidates.map((candidate) => candidate.url).join(', ');\n throw new Error(`Download failed. Tried: ${attempted.join(', ')}. URLs: ${attemptedUrls}`);\n }\n\n onProgress({\n phase: 'downloading',\n message: `Using ${selected.name} (${selected.url})`,\n });\n\n if (selected.usesRosetta) {\n onProgress({\n phase: 'downloading',\n message: `No ARM64 binary available, using x86_64 version with Rosetta 2...`,\n });\n\n await this.ensureRosettaAvailable();\n\n onProgress({\n phase: 'downloading',\n message: `Rosetta 2 available, continuing with x86_64 fallback binary...`,\n });\n }\n\n const contentLength = parseInt(response.headers.get('content-length') || '0', 10);\n\n // Stream download with progress\n const body = response.body;\n if (!body) {\n throw new Error('No response body');\n }\n\n let downloaded = 0;\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n chunks.push(value);\n downloaded += value.length;\n\n if (contentLength > 0) {\n const percent = Math.round((downloaded / contentLength) * 100);\n onProgress({\n phase: 'downloading',\n message: `Downloading... ${percent}%`,\n percent,\n });\n }\n }\n\n const buffer = Buffer.concat(chunks);\n\n // Handle different archive formats\n onProgress({ phase: 'extracting', message: 'Extracting binary...' });\n\n if (selected.name.endsWith('.tar.gz') || selected.name.endsWith('.tgz')) {\n await this.extractTarGz(buffer, binaryPath);\n } else if (selected.name.endsWith('.zip')) {\n await this.extractZip(buffer, binaryPath);\n } else {\n // Direct binary\n const { writeFile } = await import('node:fs/promises');\n await writeFile(binaryPath, buffer);\n }\n\n // Make executable (Unix)\n const { platform } = this.getPlatformInfo();\n if (platform !== 'win32') {\n chmodSync(binaryPath, 0o755);\n }\n\n onProgress({ phase: 'installing', message: `Installed to ${binaryPath}` });\n\n return this.getBinaryInfo();\n }\n\n /**\n * Extract tar.gz archive\n */\n private async extractTarGz(buffer: Buffer, targetPath: string): Promise<void> {\n const { writeFile, readdir, rename, rm } = await import('node:fs/promises');\n const tempDir = `${targetPath}.extract`;\n\n // Create temp directory\n if (!existsSync(tempDir)) {\n mkdirSync(tempDir, { recursive: true });\n }\n\n // Write archive to temp file\n const archivePath = `${tempDir}/archive.tar.gz`;\n await writeFile(archivePath, buffer);\n\n // Extract using tar command\n try {\n await execAsync(`tar -xzf \"${archivePath}\" -C \"${tempDir}\"`);\n } catch (primaryError) {\n // Fallback: use Node's built-in zlib to avoid external `gunzip` dependency\n try {\n const { gunzipSync } = await import('node:zlib');\n const tarPath = `${tempDir}/archive.tar`;\n const tarBuffer = gunzipSync(buffer);\n await writeFile(tarPath, tarBuffer);\n await execAsync(`tar -xf \"${tarPath}\" -C \"${tempDir}\"`);\n } catch (fallbackError) {\n const primaryMessage =\n primaryError instanceof Error ? primaryError.message : String(primaryError);\n const fallbackMessage =\n fallbackError instanceof Error ? fallbackError.message : String(fallbackError);\n throw new Error(\n `Failed to extract tar.gz archive. Primary: ${primaryMessage}. Fallback: ${fallbackMessage}`,\n );\n }\n }\n\n // Find the binary in extracted files\n const files = await readdir(tempDir, { recursive: true });\n const binaryFile = this.findBinaryInExtractedFiles(files, 'fnn');\n\n if (binaryFile) {\n const sourcePath = join(tempDir, String(binaryFile));\n await rename(sourcePath, targetPath);\n } else {\n // If no fnn found, maybe the archive contains a single binary\n const extractedFiles = await readdir(tempDir);\n const possibleBinary = extractedFiles.find(\n (f) => f !== 'archive.tar.gz' && !f.startsWith('.'),\n );\n if (possibleBinary) {\n await rename(join(tempDir, possibleBinary), targetPath);\n }\n }\n\n // Also extract fnn-migrate if present in the archive\n const migrateFile = this.findBinaryInExtractedFiles(files, 'fnn-migrate');\n\n if (migrateFile) {\n const migrateSourcePath = join(tempDir, String(migrateFile));\n const migrateTargetPath = this.getMigrateBinaryPath();\n try {\n // Proactively remove existing fnn-migrate so rename doesn't fail\n if (existsSync(migrateTargetPath)) {\n try {\n unlinkSync(migrateTargetPath);\n } catch {\n // If we can't remove the existing file, the rename will likely fail below\n }\n }\n await rename(migrateSourcePath, migrateTargetPath);\n const { platform } = this.getPlatformInfo();\n if (platform !== 'win32') {\n chmodSync(migrateTargetPath, 0o755);\n }\n } catch (error) {\n // fnn-migrate is optional; don't fail the main install, but warn\n const message = error instanceof Error ? error.message : String(error);\n console.warn(\n `Warning: failed to install fnn-migrate helper. Migrations may be unavailable or stale. Error: ${message}`,\n );\n }\n }\n\n // Cleanup temp directory\n await rm(tempDir, { recursive: true, force: true });\n }\n\n /**\n * Extract zip archive (primarily for Windows)\n */\n private async extractZip(buffer: Buffer, targetPath: string): Promise<void> {\n const { writeFile, readdir, rename, rm } = await import('node:fs/promises');\n const tempDir = `${targetPath}.extract`;\n\n if (!existsSync(tempDir)) {\n mkdirSync(tempDir, { recursive: true });\n }\n\n const archivePath = `${tempDir}/archive.zip`;\n await writeFile(archivePath, buffer);\n\n // Extract using unzip command\n const { platform } = this.getPlatformInfo();\n if (platform === 'win32') {\n await execAsync(\n `powershell -command \"Expand-Archive -Path '${archivePath}' -DestinationPath '${tempDir}'\"`,\n );\n } else {\n await execAsync(`unzip -o \"${archivePath}\" -d \"${tempDir}\"`);\n }\n\n // Find and move the binary\n const files = await readdir(tempDir, { recursive: true });\n const binaryFile = this.findBinaryInExtractedFiles(files, 'fnn');\n\n if (binaryFile) {\n await rename(join(tempDir, String(binaryFile)), targetPath);\n }\n\n // Also extract fnn-migrate if present\n const migrateFile = this.findBinaryInExtractedFiles(files, 'fnn-migrate');\n\n if (migrateFile) {\n const migrateTargetPath = this.getMigrateBinaryPath();\n try {\n // Proactively remove existing fnn-migrate so rename doesn't fail\n if (existsSync(migrateTargetPath)) {\n try {\n unlinkSync(migrateTargetPath);\n } catch {\n // If we can't remove the existing file, the rename will likely fail below\n }\n }\n await rename(join(tempDir, String(migrateFile)), migrateTargetPath);\n const { platform } = this.getPlatformInfo();\n if (platform !== 'win32') {\n chmodSync(migrateTargetPath, 0o755);\n }\n } catch (error) {\n // fnn-migrate is optional; don't fail the main install, but warn\n const message = error instanceof Error ? error.message : String(error);\n console.warn(\n `Warning: failed to install fnn-migrate helper. Migrations may be unavailable or stale. Error: ${message}`,\n );\n }\n }\n\n await rm(tempDir, { recursive: true, force: true });\n }\n\n /**\n * Remove the installed binary\n */\n async uninstall(): Promise<void> {\n const binaryPath = this.getBinaryPath();\n if (existsSync(binaryPath)) {\n unlinkSync(binaryPath);\n }\n }\n\n /**\n * Find a named binary in a list of extracted file paths.\n */\n private findBinaryInExtractedFiles(\n files: (string | Buffer)[],\n binaryName: 'fnn' | 'fnn-migrate',\n ): string | Buffer | undefined {\n return files.find((f) => {\n const name = String(f);\n return (\n name.endsWith(`/${binaryName}`) ||\n name === binaryName ||\n name.endsWith(`\\\\${binaryName}`) ||\n name.endsWith(`${binaryName}.exe`)\n );\n });\n }\n}\n\n// =============================================================================\n// Convenience Functions\n// =============================================================================\n\n/**\n * Download the Fiber binary to the default location\n */\nexport async function downloadFiberBinary(options: DownloadOptions = {}): Promise<BinaryInfo> {\n const manager = new BinaryManager(options.installDir);\n return manager.download(options);\n}\n\n/**\n * Get information about the installed binary\n */\nexport async function getFiberBinaryInfo(installDir?: string): Promise<BinaryInfo> {\n const manager = new BinaryManager(installDir);\n return manager.getBinaryInfo();\n}\n\n/**\n * Ensure the Fiber binary is available, downloading if necessary.\n * If the binary exists but its version does not match the requested\n * (or default) version, it will be re-downloaded.\n */\nexport async function ensureFiberBinary(options: DownloadOptions = {}): Promise<string> {\n const manager = new BinaryManager(options.installDir);\n const info = await manager.getBinaryInfo();\n let downloadOptions = options;\n\n if (info.ready) {\n const wantedTag = manager.normalizeTag(options.version || DEFAULT_FIBER_VERSION);\n const wantedVersion = wantedTag.startsWith('v') ? wantedTag.slice(1) : wantedTag;\n if (info.version === wantedVersion) {\n return info.path;\n }\n // Version mismatch — force re-download.\n downloadOptions = { ...options, force: true };\n }\n\n const downloaded = await manager.download(downloadOptions);\n return downloaded.path;\n}\n\n/**\n * Get the default binary path\n */\nexport function getDefaultBinaryPath(): string {\n const manager = new BinaryManager();\n return manager.getBinaryPath();\n}\n","/**\n * Migration Manager\n * Handles Fiber node database migration when upgrading between versions.\n *\n * Uses the `fnn-migrate` binary shipped in Fiber release archives to migrate\n * the on-disk store format so that it is compatible with a newer `fnn` binary.\n */\n\nimport { execFile } from 'node:child_process';\nimport { cpSync, existsSync, mkdirSync, renameSync, rmSync, statSync } from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface MigrationCheckResult {\n /** Whether migration is needed */\n needed: boolean;\n /** Whether the store is valid (parseable) */\n valid: boolean;\n /** Human-readable status message */\n message: string;\n /** Path to the store that was checked */\n storePath: string;\n}\n\nexport interface MigrationResult {\n /** Whether migration succeeded */\n success: boolean;\n /** Path to backup directory (if created) */\n backupPath?: string;\n /** Human-readable message */\n message: string;\n /** Detailed output from fnn-migrate */\n output?: string;\n}\n\nexport interface MigrationOptions {\n /** Path to the fiber store directory (typically `<dataDir>/fiber/store`) */\n storePath: string;\n /** Create a backup before migrating (default: true) */\n backup?: boolean;\n /** Directory to place backups in (default: sibling of storePath) */\n backupDir?: string;\n /**\n * Force migration attempt even when pre-check reports incompatible data.\n * Use carefully: migration command may still fail and store may require\n * manual recovery; backup is strongly recommended.\n */\n force?: boolean;\n}\n\n// =============================================================================\n// Migration Manager\n// =============================================================================\n\nexport class MigrationManager {\n private migrateBinaryPath: string;\n\n constructor(migrateBinaryPath: string) {\n this.migrateBinaryPath = migrateBinaryPath;\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n /**\n * Check whether the store needs migration or is incompatible.\n *\n * Runs `fnn-migrate -p <storePath> --check-validate` which exits 0 on\n * success (no migration needed) and exits 1 with a message otherwise.\n */\n async check(storePath: string): Promise<MigrationCheckResult> {\n this.ensureBinaryExists();\n\n if (!existsSync(storePath)) {\n return {\n needed: false,\n valid: true,\n message: 'Store does not exist yet — no migration needed.',\n storePath,\n };\n }\n\n try {\n const { stdout } = await execFileAsync(this.migrateBinaryPath, [\n '-p',\n storePath,\n '--check-validate',\n ]);\n const output = stdout.trim();\n if (output.includes('validate success')) {\n return {\n needed: false,\n valid: true,\n message: 'Store is up-to-date, no migration needed.',\n storePath,\n };\n }\n return {\n needed: false,\n valid: true,\n message: output || 'Store validation passed.',\n storePath,\n };\n } catch (error) {\n const stderr = this.extractStderr(error);\n const isIncompatible =\n stderr.includes('incompatible database') || stderr.includes('need to upgrade');\n const needsMigration =\n stderr.includes('need to run database migration') || stderr.includes('need to migrate');\n const needsCleanStart =\n stderr.includes('shutdown all channels') || stderr.includes('shutdown all old channels');\n\n if (needsCleanStart) {\n return {\n needed: true,\n valid: false,\n message:\n 'Store requires a breaking migration that cannot be auto-migrated. ' +\n 'You need to:\\n' +\n ' 1. Start the OLD version of fnn\\n' +\n ' 2. Close all channels (cooperative or forced)\\n' +\n ' 3. Stop the old node\\n' +\n ' 4. Remove the store directory\\n' +\n ' 5. Start the new fnn version with a fresh database\\n\\n' +\n 'See: https://github.com/nervosnetwork/fiber/wiki/Fiber-Breaking-Change-Migration-Guide',\n storePath,\n };\n }\n\n if (needsMigration) {\n return {\n needed: true,\n valid: true,\n message: 'Store needs migration. Run `fiber-pay node upgrade` to migrate.',\n storePath,\n };\n }\n\n if (isIncompatible) {\n return {\n needed: true,\n valid: false,\n message: `Store is incompatible: ${stderr}`,\n storePath,\n };\n }\n\n return {\n needed: true,\n valid: false,\n message: `Store validation failed: ${stderr}`,\n storePath,\n };\n }\n }\n\n /**\n * Create a timestamped backup of the store directory.\n *\n * @returns The path to the created backup directory.\n */\n backup(storePath: string, backupDir?: string): string {\n if (!existsSync(storePath)) {\n throw new Error(`Store path does not exist: ${storePath}`);\n }\n\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n const storeName = basename(storePath);\n const targetDir = backupDir || dirname(storePath);\n const backupPath = join(targetDir, `${storeName}.bak-${timestamp}`);\n\n mkdirSync(backupPath, { recursive: true });\n cpSync(storePath, backupPath, { recursive: true });\n\n return backupPath;\n }\n\n /**\n * Run the database migration.\n *\n * Optionally creates a backup first. Uses `--skip-confirm` to avoid\n * interactive prompts.\n */\n async migrate(options: MigrationOptions): Promise<MigrationResult> {\n const { storePath, backup: doBackup = true, backupDir, force = false } = options;\n\n this.ensureBinaryExists();\n\n if (!existsSync(storePath)) {\n return {\n success: true,\n message: 'Store does not exist — nothing to migrate.',\n };\n }\n\n // Pre-flight check\n const checkResult = await this.check(storePath);\n\n if (!checkResult.needed) {\n return {\n success: true,\n message: checkResult.message,\n };\n }\n\n if (!checkResult.valid && !force) {\n return {\n success: false,\n message: checkResult.message,\n };\n }\n\n // Backup\n let backupPath: string | undefined;\n if (doBackup) {\n try {\n backupPath = this.backup(storePath, backupDir);\n } catch (backupError) {\n const msg = backupError instanceof Error ? backupError.message : String(backupError);\n return {\n success: false,\n message: `Failed to create backup before migration: ${msg}`,\n };\n }\n }\n\n // Run migration\n try {\n const { stdout, stderr } = await execFileAsync(this.migrateBinaryPath, [\n '-p',\n storePath,\n '--skip-confirm',\n ]);\n const output = `${stdout}\\n${stderr}`.trim();\n\n if (output.includes('migrated successfully') || output.includes('db migrated')) {\n return {\n success: true,\n backupPath,\n message: 'Migration completed successfully.',\n output,\n };\n }\n\n // Command exited 0 but no recognized success message — treat as failure to be safe\n let ambiguousMessage = `Migration command finished without errors, but the expected success message was not found. Output: ${output}`;\n if (backupPath) {\n ambiguousMessage += `\\n\\nA backup was created at: ${backupPath}\\nTo roll back, delete the current store at \"${storePath}\" and restore the backup from that path.`;\n }\n return {\n success: false,\n backupPath,\n message: ambiguousMessage,\n output,\n };\n } catch (error) {\n const stderr = this.extractStderr(error);\n\n // Offer rollback information\n let message = `Migration failed: ${stderr}`;\n if (backupPath) {\n message += `\\n\\nA backup was created at: ${backupPath}\\nTo roll back, delete the current store at \"${storePath}\" and restore the backup from that path.`;\n }\n\n return {\n success: false,\n backupPath,\n message,\n output: stderr,\n };\n }\n }\n\n /**\n * Rollback a migration by restoring a backup.\n */\n rollback(storePath: string, backupPath: string): void {\n if (!existsSync(backupPath)) {\n throw new Error(`Backup path does not exist: ${backupPath}`);\n }\n\n // Remove the (potentially corrupted) current store\n if (existsSync(storePath)) {\n rmSync(storePath, { recursive: true, force: true });\n }\n\n // Restore from backup\n renameSync(backupPath, storePath);\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Resolve the store path from a data directory.\n *\n * The fiber node stores its database at `<dataDir>/fiber/store`.\n */\n static resolveStorePath(dataDir: string): string {\n return join(dataDir, 'fiber', 'store');\n }\n\n /**\n * Check if the store directory exists and is a directory.\n */\n static storeExists(dataDir: string): boolean {\n const storePath = MigrationManager.resolveStorePath(dataDir);\n if (!existsSync(storePath)) return false;\n try {\n const stats = statSync(storePath);\n return stats.isDirectory();\n } catch {\n return false;\n }\n }\n\n private ensureBinaryExists(): void {\n if (!existsSync(this.migrateBinaryPath)) {\n throw new Error(\n `fnn-migrate binary not found at: ${this.migrateBinaryPath}\\n` +\n 'This binary is required for database migration.\\n' +\n 'Re-download the Fiber binary with: fiber-pay binary download --force',\n );\n }\n }\n\n private extractStderr(error: unknown): string {\n if (error && typeof error === 'object') {\n const e = error as { stderr?: string; stdout?: string; message?: string };\n return (e.stderr || e.stdout || e.message || String(error)).trim();\n }\n return String(error);\n }\n}\n","/**\n * Process Manager\n * Manages the lifecycle of the Fiber Network Node (fnn) binary\n */\n\nimport { type ChildProcess, spawn } from 'node:child_process';\nimport { EventEmitter } from 'node:events';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport * as yaml from './yaml.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface FiberNodeConfig {\n /** Path to the fnn binary */\n binaryPath: string;\n /** Base directory for data storage */\n dataDir: string;\n /** Path to the config file (optional - will use built-in testnet config if not provided) */\n configFilePath?: string;\n /** Fiber P2P listening address */\n fiberListeningAddr?: string;\n /** Fiber node name */\n nodeName?: string;\n /** Bootstrap node addresses */\n bootnodeAddrs?: string[];\n /** CKB RPC URL */\n ckbRpcUrl?: string;\n /** RPC listening address */\n rpcListeningAddr?: string;\n /** Chain configuration (mainnet, testnet, or file path) */\n chain?: 'mainnet' | 'testnet' | string;\n /** Key encryption password */\n keyPassword?: string;\n /** Log level */\n logLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error';\n /** UDT whitelist */\n udtWhitelist?: Array<{\n name: string;\n script: {\n code_hash: string;\n hash_type: 'type' | 'data' | 'data1' | 'data2';\n args: string;\n };\n }>;\n}\n\nexport interface ProcessManagerEvents {\n started: () => void;\n stopped: (code: number | null, signal: NodeJS.Signals | null) => void;\n error: (error: Error) => void;\n stdout: (data: string) => void;\n stderr: (data: string) => void;\n ready: () => void;\n}\n\nexport type ProcessState = 'stopped' | 'starting' | 'running' | 'stopping';\n\nconst DEFAULT_TESTNET_FIBER_CONFIG = {\n listening_addr: '/ip4/0.0.0.0/tcp/8228',\n bootnode_addrs: [\n '/ip4/54.179.226.154/tcp/8228/p2p/Qmes1EBD4yNo9Ywkfe6eRw9tG1nVNGLDmMud1xJMsoYFKy',\n '/ip4/16.163.7.105/tcp/8228/p2p/QmdyQWjPtbK4NWWsvy8s69NGJaQULwgeQDT5ZpNDrTNaeV',\n ],\n announce_listening_addr: true,\n chain: 'testnet',\n scripts: [\n {\n name: 'FundingLock',\n script: {\n code_hash: '0x6c67887fe201ee0c7853f1682c0b77c0e6214044c156c7558269390a8afa6d7c',\n hash_type: 'type',\n args: '0x',\n },\n cell_deps: [\n {\n type_id: {\n code_hash: '0x00000000000000000000000000000000000000000000000000545950455f4944',\n hash_type: 'type',\n args: '0x3cb7c0304fe53f75bb5727e2484d0beae4bd99d979813c6fc97c3cca569f10f6',\n },\n },\n {\n cell_dep: {\n out_point: {\n tx_hash: '0x12c569a258dd9c5bd99f632bb8314b1263b90921ba31496467580d6b79dd14a7',\n index: '0x0',\n },\n dep_type: 'code',\n },\n },\n ],\n },\n {\n name: 'CommitmentLock',\n script: {\n code_hash: '0x740dee83f87c6f309824d8fd3fbdd3c8380ee6fc9acc90b1a748438afcdf81d8',\n hash_type: 'type',\n args: '0x',\n },\n cell_deps: [\n {\n type_id: {\n code_hash: '0x00000000000000000000000000000000000000000000000000545950455f4944',\n hash_type: 'type',\n args: '0xf7e458887495cf70dd30d1543cad47dc1dfe9d874177bf19291e4db478d5751b',\n },\n },\n {\n cell_dep: {\n out_point: {\n tx_hash: '0x12c569a258dd9c5bd99f632bb8314b1263b90921ba31496467580d6b79dd14a7',\n index: '0x0',\n },\n dep_type: 'code',\n },\n },\n ],\n },\n ],\n} as const;\n\n// =============================================================================\n// Process Manager\n// =============================================================================\n\nexport class ProcessManager extends EventEmitter {\n private config: FiberNodeConfig;\n private process: ChildProcess | null = null;\n private state: ProcessState = 'stopped';\n private configPath: string;\n private stdoutBuffer: string[] = [];\n private stderrBuffer: string[] = [];\n private maxBufferSize = 1000;\n\n constructor(config: FiberNodeConfig) {\n super();\n this.config = config;\n this.configPath = join(config.dataDir, 'config.yml');\n }\n\n /**\n * Get current process state\n */\n getState(): ProcessState {\n return this.state;\n }\n\n /**\n * Check if the process is running\n */\n isRunning(): boolean {\n return this.state === 'running' || this.state === 'starting';\n }\n\n /**\n * Start the Fiber node\n */\n async start(): Promise<void> {\n if (this.isRunning()) {\n throw new Error('Node is already running');\n }\n\n this.state = 'starting';\n\n // Ensure data directory exists\n if (!existsSync(this.config.dataDir)) {\n mkdirSync(this.config.dataDir, { recursive: true });\n }\n\n // Copy or generate config file\n await this.ensureConfigFile();\n\n // Build environment variables\n const env: Record<string, string> = {\n ...process.env,\n RUST_LOG: this.config.logLevel || 'info',\n };\n\n // FIBER_SECRET_KEY_PASSWORD is always required by the fiber node\n // Use the provided password or generate a default one\n env.FIBER_SECRET_KEY_PASSWORD = this.config.keyPassword || 'fiber-pay-default-key';\n\n // Spawn the process\n const args = ['-c', this.configPath, '-d', this.config.dataDir];\n\n this.process = spawn(this.config.binaryPath, args, {\n env,\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: false,\n });\n\n // Handle stdout\n this.process.stdout?.on('data', (data: Buffer) => {\n const text = data.toString();\n this.stdoutBuffer.push(text);\n if (this.stdoutBuffer.length > this.maxBufferSize) {\n this.stdoutBuffer.shift();\n }\n this.emit('stdout', text);\n\n // Check for ready signal\n if (text.includes('RPC server started') || text.includes('listening on')) {\n if (this.state === 'starting') {\n this.state = 'running';\n this.emit('ready');\n }\n }\n });\n\n // Handle stderr\n this.process.stderr?.on('data', (data: Buffer) => {\n const text = data.toString();\n this.stderrBuffer.push(text);\n if (this.stderrBuffer.length > this.maxBufferSize) {\n this.stderrBuffer.shift();\n }\n this.emit('stderr', text);\n });\n\n // Handle process exit\n this.process.on('exit', (code, signal) => {\n this.state = 'stopped';\n this.process = null;\n this.emit('stopped', code, signal);\n });\n\n // Handle process error\n this.process.on('error', (error) => {\n this.state = 'stopped';\n this.process = null;\n this.emit('error', error);\n });\n\n this.emit('started');\n\n // Wait a bit for the process to initialize\n await new Promise((resolve) => setTimeout(resolve, 500));\n\n // If process died immediately, throw error\n // State may have changed due to async event handlers\n if ((this.state as ProcessState) === 'stopped') {\n throw new Error('Process exited immediately. Check logs.');\n }\n }\n\n /**\n * Stop the Fiber node\n */\n async stop(timeout = 10000): Promise<void> {\n if (!this.process || this.state === 'stopped') {\n return;\n }\n\n this.state = 'stopping';\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n // Force kill if graceful shutdown fails\n this.process?.kill('SIGKILL');\n }, timeout);\n\n this.once('stopped', () => {\n clearTimeout(timer);\n resolve();\n });\n\n this.once('error', (error) => {\n clearTimeout(timer);\n reject(error);\n });\n\n // Send SIGTERM for graceful shutdown\n this.process?.kill('SIGTERM');\n });\n }\n\n /**\n * Restart the Fiber node\n */\n async restart(): Promise<void> {\n await this.stop();\n await this.start();\n }\n\n /**\n * Get recent stdout output\n */\n getStdout(lines?: number): string[] {\n if (lines) {\n return this.stdoutBuffer.slice(-lines);\n }\n return [...this.stdoutBuffer];\n }\n\n /**\n * Get recent stderr output\n */\n getStderr(lines?: number): string[] {\n if (lines) {\n return this.stderrBuffer.slice(-lines);\n }\n return [...this.stderrBuffer];\n }\n\n /**\n * Get the RPC URL for this node\n */\n getRpcUrl(): string {\n const addr = this.config.rpcListeningAddr || '127.0.0.1:8227';\n return `http://${addr}`;\n }\n\n /**\n * Wait for the node to be ready\n */\n waitForReady(timeout = 60000): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.state === 'running') {\n resolve();\n return;\n }\n\n const timer = setTimeout(() => {\n this.off('ready', onReady);\n this.off('stopped', onStopped);\n reject(new Error('Timeout waiting for node to be ready'));\n }, timeout);\n\n const onReady = () => {\n clearTimeout(timer);\n this.off('stopped', onStopped);\n resolve();\n };\n\n const onStopped = () => {\n clearTimeout(timer);\n this.off('ready', onReady);\n reject(new Error('Node stopped while waiting for ready'));\n };\n\n this.once('ready', onReady);\n this.once('stopped', onStopped);\n });\n }\n\n /**\n * Ensure the config file exists (copy from source or generate)\n */\n private async ensureConfigFile(): Promise<void> {\n const configDir = dirname(this.configPath);\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n // If a config file path is provided, copy it\n if (this.config.configFilePath && existsSync(this.config.configFilePath)) {\n // Copy the config file to the data directory\n const sourceContent = readFileSync(this.config.configFilePath, 'utf-8');\n writeFileSync(this.configPath, sourceContent);\n return;\n }\n\n // Otherwise, generate a basic config file\n this.generateConfigFile();\n }\n\n /**\n * Generate the config file (fallback when no source config provided)\n */\n private generateConfigFile(): void {\n const chain = this.config.chain || 'testnet';\n const useDefaultTestnetConfig = chain === 'testnet';\n const config: Record<string, unknown> = {\n fiber: useDefaultTestnetConfig\n ? { ...DEFAULT_TESTNET_FIBER_CONFIG }\n : {\n listening_addr: this.config.fiberListeningAddr || '/ip4/127.0.0.1/tcp/8228',\n announce_listening_addr: true,\n chain,\n },\n rpc: {\n listening_addr: this.config.rpcListeningAddr || '127.0.0.1:8227',\n },\n ckb: {\n rpc_url: this.config.ckbRpcUrl || 'https://testnet.ckbapp.dev/',\n },\n services: ['fiber', 'rpc', 'ckb'],\n };\n\n if (this.config.nodeName) {\n (config.fiber as Record<string, unknown>).announced_node_name = this.config.nodeName;\n }\n\n if (this.config.bootnodeAddrs?.length) {\n (config.fiber as Record<string, unknown>).bootnode_addrs = this.config.bootnodeAddrs;\n }\n\n if (this.config.udtWhitelist?.length) {\n (config.ckb as Record<string, unknown>).udt_whitelist = this.config.udtWhitelist;\n }\n\n const configDir = dirname(this.configPath);\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n writeFileSync(this.configPath, yaml.stringify(config));\n }\n}\n","/**\n * Simple YAML serializer\n * Minimal implementation for config file generation\n */\n\nexport function stringify(obj: unknown, indent = 0): string {\n const spaces = ' '.repeat(indent);\n\n if (obj === null || obj === undefined) {\n return 'null';\n }\n\n if (typeof obj === 'string') {\n // Quote strings that need it\n if (\n obj.includes(':') ||\n obj.includes('#') ||\n obj.includes('\\n') ||\n obj.startsWith(' ') ||\n obj.endsWith(' ') ||\n obj === '' ||\n obj === 'true' ||\n obj === 'false' ||\n !Number.isNaN(Number(obj))\n ) {\n return JSON.stringify(obj);\n }\n return obj;\n }\n\n if (typeof obj === 'number' || typeof obj === 'boolean') {\n return String(obj);\n }\n\n if (Array.isArray(obj)) {\n if (obj.length === 0) {\n return '[]';\n }\n return obj\n .map((item) => {\n const value = stringify(item, indent + 1);\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n // Multi-line object in array\n const lines = value.split('\\n');\n return `${spaces}- ${lines[0]}\\n${lines\n .slice(1)\n .map((l) => `${spaces} ${l}`)\n .join('\\n')}`;\n }\n return `${spaces}- ${value}`;\n })\n .join('\\n');\n }\n\n if (typeof obj === 'object') {\n const entries = Object.entries(obj as Record<string, unknown>);\n if (entries.length === 0) {\n return '{}';\n }\n return entries\n .map(([key, value]) => {\n const valueStr = stringify(value, indent + 1);\n if (\n typeof value === 'object' &&\n value !== null &&\n !(Array.isArray(value) && value.length === 0) &&\n !(typeof value === 'object' && Object.keys(value).length === 0)\n ) {\n return `${spaces}${key}:\\n${valueStr}`;\n }\n return `${spaces}${key}: ${valueStr}`;\n })\n .join('\\n');\n }\n\n return String(obj);\n}\n\nexport function parse(yaml: string): unknown {\n // Basic YAML parsing - for production use a proper library\n const lines = yaml.split('\\n');\n const result: Record<string, unknown> = {};\n const stack: Array<{ indent: number; obj: Record<string, unknown>; key?: string }> = [\n { indent: -1, obj: result },\n ];\n\n for (const line of lines) {\n // Skip empty lines and comments\n if (!line.trim() || line.trim().startsWith('#')) {\n continue;\n }\n\n const indent = line.search(/\\S/);\n const content = line.trim();\n\n // Handle key: value\n const colonIndex = content.indexOf(':');\n if (colonIndex > 0) {\n const key = content.slice(0, colonIndex).trim();\n const value = content.slice(colonIndex + 1).trim();\n\n // Pop stack to correct level\n while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {\n stack.pop();\n }\n\n const parent = stack[stack.length - 1].obj;\n\n if (value === '' || value === '|' || value === '>') {\n // Nested object\n const newObj: Record<string, unknown> = {};\n parent[key] = newObj;\n stack.push({ indent, obj: newObj, key });\n } else {\n // Primitive value\n parent[key] = parseValue(value);\n }\n }\n }\n\n return result;\n}\n\nfunction parseValue(value: string): unknown {\n // Remove quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n\n // Boolean\n if (value === 'true') return true;\n if (value === 'false') return false;\n\n // Null\n if (value === 'null' || value === '~') return null;\n\n // Number\n const num = Number(value);\n if (!Number.isNaN(num)) return num;\n\n // Array (inline)\n if (value.startsWith('[') && value.endsWith(']')) {\n return JSON.parse(value);\n }\n\n return value;\n}\n","/**\n * Key Manager\n * Handles generation, storage, and encryption of Fiber node keys\n * Keys are isolated from LLM context for security\n */\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { KeyConfig, KeyInfo } from '@fiber-pay/sdk';\nimport { decryptKey, derivePublicKey, generatePrivateKey, isEncryptedKey } from '@fiber-pay/sdk';\n\n// =============================================================================\n// Key Manager\n// =============================================================================\n\nexport class KeyManager {\n private config: KeyConfig;\n private fiberKeyPath: string;\n private ckbKeyPath: string;\n\n constructor(config: KeyConfig) {\n this.config = config;\n this.fiberKeyPath = join(config.baseDir, 'fiber', 'sk');\n this.ckbKeyPath = join(config.baseDir, 'ckb', 'key');\n }\n\n /**\n * Initialize keys - generate if they don't exist and autoGenerate is true\n */\n async initialize(): Promise<{ fiber: KeyInfo; ckb: KeyInfo }> {\n const fiberExists = existsSync(this.fiberKeyPath);\n const ckbExists = existsSync(this.ckbKeyPath);\n\n if (!fiberExists || !ckbExists) {\n if (!this.config.autoGenerate) {\n throw new Error(\n `Keys not found and autoGenerate is disabled. ` +\n `Missing: ${[!fiberExists && 'fiber', !ckbExists && 'ckb'].filter(Boolean).join(', ')}`,\n );\n }\n }\n\n // Generate missing keys\n if (!fiberExists) {\n await this.generateKey('fiber');\n }\n if (!ckbExists) {\n await this.generateKey('ckb');\n }\n\n return {\n fiber: await this.getKeyInfo('fiber'),\n ckb: await this.getKeyInfo('ckb'),\n };\n }\n\n /**\n * Generate a new key\n */\n async generateKey(type: 'fiber' | 'ckb'): Promise<KeyInfo> {\n const keyPath = type === 'fiber' ? this.fiberKeyPath : this.ckbKeyPath;\n const keyDir = dirname(keyPath);\n\n // Create directory if it doesn't exist\n if (!existsSync(keyDir)) {\n mkdirSync(keyDir, { recursive: true });\n }\n\n // Generate 32 random bytes\n const privateKey = generatePrivateKey();\n\n // The fiber node expects different formats:\n // - fiber/sk: raw 32 bytes\n // - ckb/key: hex string (64 characters)\n let keyData: string | Uint8Array;\n if (type === 'fiber') {\n keyData = privateKey;\n } else {\n keyData = Buffer.from(privateKey).toString('hex');\n }\n\n // Write key file with restricted permissions\n writeFileSync(keyPath, keyData);\n chmodSync(keyPath, 0o600);\n\n return this.getKeyInfo(type);\n }\n\n /**\n * Get information about a key (without exposing the private key)\n */\n async getKeyInfo(type: 'fiber' | 'ckb'): Promise<KeyInfo> {\n const keyPath = type === 'fiber' ? this.fiberKeyPath : this.ckbKeyPath;\n\n if (!existsSync(keyPath)) {\n throw new Error(`Key not found: ${keyPath}`);\n }\n\n const keyData = readFileSync(keyPath);\n const encrypted = isEncryptedKey(keyData);\n\n // Get private key to derive public key\n const privateKey = await this.loadPrivateKey(type);\n const publicKey = await derivePublicKey(privateKey);\n\n return {\n publicKey,\n encrypted,\n path: keyPath,\n createdAt: Date.now(), // TODO: get actual file creation time\n };\n }\n\n /**\n * Load and decrypt a private key (for internal use only)\n * This should NEVER be exposed to the LLM context\n */\n private async loadPrivateKey(type: 'fiber' | 'ckb'): Promise<Uint8Array> {\n const keyPath = type === 'fiber' ? this.fiberKeyPath : this.ckbKeyPath;\n const keyData = readFileSync(keyPath);\n\n if (isEncryptedKey(keyData)) {\n if (!this.config.encryptionPassword) {\n throw new Error('Key is encrypted but no password provided');\n }\n return await decryptKey(keyData, this.config.encryptionPassword);\n }\n\n // The fiber node stores keys in different formats:\n // - fiber/sk: raw 32 bytes\n // - ckb/key: hex string (64 characters)\n if (type === 'fiber') {\n return new Uint8Array(keyData);\n } else {\n const hexString = keyData.toString('utf-8').trim();\n return new Uint8Array(Buffer.from(hexString, 'hex'));\n }\n }\n\n /**\n * Export keys for use with the Fiber node process\n * Returns the password to use for FIBER_SECRET_KEY_PASSWORD env var\n */\n getNodeKeyConfig(): { password?: string } {\n return {\n password: this.config.encryptionPassword,\n };\n }\n}\n\n/**\n * Create a key manager with environment-based configuration\n */\nexport function createKeyManager(baseDir: string, options?: Partial<KeyConfig>): KeyManager {\n const password = process.env.FIBER_KEY_PASSWORD || options?.encryptionPassword;\n\n return new KeyManager({\n baseDir,\n encryptionPassword: password,\n autoGenerate: options?.autoGenerate ?? true,\n });\n}\n"],"mappings":"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","names":["platform","existsSync","mkdirSync","join","promisify","existsSync","mkdirSync","dirname","join","join","existsSync","mkdirSync","dirname","chmodSync","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/binary/manager.ts","../src/migration/manager.ts","../src/process/manager.ts","../src/process/yaml.ts","../src/security/key-manager.ts"],"sourcesContent":["/**\n * Shared constants for the @fiber-pay/node package\n */\n\n/** Default Fiber Network Node binary version used for downloads when no version is specified. */\nexport const DEFAULT_FIBER_VERSION = 'v0.8.0';\n","/**\n * Binary Manager\n * Handles downloading, installing, and managing the Fiber Network Node (fnn) binary\n */\n\nimport { exec } from 'node:child_process';\nimport { chmodSync, existsSync, mkdirSync, unlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { DEFAULT_FIBER_VERSION } from '../constants.js';\n\nconst execAsync = promisify(exec);\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type Platform = 'darwin' | 'linux' | 'win32';\nexport type Arch = 'x64' | 'arm64';\n\nexport interface BinaryInfo {\n /** Path to the binary */\n path: string;\n /** Version of the binary */\n version: string;\n /** Whether the binary exists and is executable */\n ready: boolean;\n}\n\nexport interface DownloadOptions {\n /** Target directory for the binary */\n installDir?: string;\n /** Specific version to download (default: latest) */\n version?: string;\n /** Force re-download even if binary exists */\n force?: boolean;\n /** Progress callback */\n onProgress?: (progress: DownloadProgress) => void;\n}\n\nexport interface DownloadProgress {\n phase: 'fetching' | 'downloading' | 'extracting' | 'installing';\n percent?: number;\n message: string;\n}\n\ninterface AssetCandidate {\n name: string;\n url: string;\n usesRosetta: boolean;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst GITHUB_REPO = 'nervosnetwork/fiber';\nconst GITHUB_RELEASES_URL = `https://github.com/${GITHUB_REPO}/releases`;\nconst DEFAULT_INSTALL_DIR = join(process.env.HOME || '~', '.fiber-pay', 'bin');\nconst RELEASE_TAG_PATTERN = /^v\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/;\n\n// Binary naming patterns for different platforms\n// Pattern used to match assets: fnn_vX.X.X-{pattern}.tar.gz\nconst BINARY_PATTERNS: Record<Platform, Record<Arch, string>> = {\n darwin: {\n x64: 'x86_64-darwin',\n arm64: 'aarch64-darwin', // May not exist yet, will fallback to x64\n },\n linux: {\n x64: 'x86_64-linux',\n arm64: 'aarch64-linux',\n },\n win32: {\n x64: 'x86_64-windows',\n arm64: 'aarch64-windows',\n },\n};\n\n// =============================================================================\n// Binary Manager\n// =============================================================================\n\nexport class BinaryManager {\n private installDir: string;\n\n constructor(installDir?: string) {\n this.installDir = installDir || DEFAULT_INSTALL_DIR;\n }\n\n /**\n * Get the current platform and architecture\n */\n getPlatformInfo(): { platform: Platform; arch: Arch } {\n const platform = process.platform as Platform;\n const arch = process.arch === 'arm64' ? 'arm64' : 'x64';\n\n if (!['darwin', 'linux', 'win32'].includes(platform)) {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n return { platform, arch };\n }\n\n /**\n * Get the pattern to match for the current platform\n */\n getAssetPattern(): string {\n const { platform, arch } = this.getPlatformInfo();\n const pattern = BINARY_PATTERNS[platform]?.[arch];\n\n if (!pattern) {\n throw new Error(`No binary pattern for ${platform}/${arch}`);\n }\n\n return pattern;\n }\n\n /**\n * Get the path where the binary should be installed\n */\n getBinaryPath(): string {\n const { platform } = this.getPlatformInfo();\n const binaryName = platform === 'win32' ? 'fnn.exe' : 'fnn';\n return join(this.installDir, binaryName);\n }\n\n /**\n * Get the path where the fnn-migrate binary should be installed\n */\n getMigrateBinaryPath(): string {\n const { platform } = this.getPlatformInfo();\n const binaryName = platform === 'win32' ? 'fnn-migrate.exe' : 'fnn-migrate';\n return join(this.installDir, binaryName);\n }\n\n /**\n * Check if the binary is installed and get its info\n */\n async getBinaryInfo(): Promise<BinaryInfo> {\n const binaryPath = this.getBinaryPath();\n const exists = existsSync(binaryPath);\n\n let version = 'unknown';\n let ready = false;\n\n if (exists) {\n try {\n const { stdout } = await execAsync(`\"${binaryPath}\" --version`);\n // Output format: \"fnn Fiber v0.7.1 (f761b6d 2026-01-14)\"\n // Extract the version number\n const versionMatch = stdout.match(/v(\\d+\\.\\d+\\.\\d+)/);\n version = versionMatch ? versionMatch[1] : stdout.trim();\n ready = true;\n } catch {\n // Binary exists but may not be executable\n ready = false;\n }\n }\n\n return { path: binaryPath, version, ready };\n }\n\n /**\n * Fetch the latest release tag from GitHub (no API, follows redirect)\n */\n async getLatestTag(): Promise<string> {\n const response = await fetch(`${GITHUB_RELEASES_URL}/latest`, {\n redirect: 'manual',\n headers: {\n 'User-Agent': 'fiber-pay',\n },\n });\n\n const location = response.headers.get('location') || response.url;\n if (!location) {\n throw new Error(`Failed to resolve latest release tag (status: ${response.status})`);\n }\n\n const match = location.match(/\\/tag\\/([^/?#]+)/);\n if (!match) {\n throw new Error(`Failed to parse release tag from redirect: ${location}`);\n }\n\n return match[1];\n }\n\n /**\n * Normalize a version into a release tag\n */\n normalizeTag(version: string): string {\n const input = version.trim();\n if (!input) {\n throw new Error('Version cannot be empty');\n }\n\n const tag = input.startsWith('v') ? input : `v${input}`;\n if (!RELEASE_TAG_PATTERN.test(tag)) {\n throw new Error(\n `Invalid version format: ${version}. Expected semver-like tag, e.g. v0.7.1 or v0.7.1-rc.1`,\n );\n }\n\n return tag;\n }\n\n /**\n * Build download candidates for the current platform\n */\n buildAssetCandidates(tag: string): AssetCandidate[] {\n const { platform, arch } = this.getPlatformInfo();\n const extensions = platform === 'win32' ? ['zip', 'tar.gz'] : ['tar.gz'];\n const variants = platform === 'win32' ? ['', '-portable'] : ['-portable', ''];\n const patterns: Array<{ pattern: string; usesRosetta: boolean }> = [\n { pattern: BINARY_PATTERNS[platform][arch], usesRosetta: false },\n ];\n\n if (platform === 'darwin' && arch === 'arm64') {\n patterns.push({ pattern: BINARY_PATTERNS.darwin.x64, usesRosetta: true });\n }\n\n const candidates: AssetCandidate[] = [];\n for (const { pattern, usesRosetta } of patterns) {\n for (const variant of variants) {\n for (const ext of extensions) {\n const name = `fnn_${tag}-${pattern}${variant}.${ext}`;\n const url = `${GITHUB_RELEASES_URL}/download/${tag}/${name}`;\n candidates.push({ name, url, usesRosetta });\n }\n }\n }\n\n return candidates;\n }\n\n /**\n * Validate Rosetta support when falling back to x86_64 binary on Apple Silicon.\n */\n private async ensureRosettaAvailable(): Promise<void> {\n const { platform, arch } = this.getPlatformInfo();\n if (platform !== 'darwin' || arch !== 'arm64') {\n return;\n }\n\n try {\n await execAsync('arch -x86_64 /usr/bin/true');\n } catch {\n throw new Error(\n 'Apple Silicon fallback selected x86_64 binary, but Rosetta 2 is not available. ' +\n 'Install Rosetta with: softwareupdate --install-rosetta --agree-to-license',\n );\n }\n }\n\n /**\n * Download and install the Fiber binary\n */\n async download(options: DownloadOptions = {}): Promise<BinaryInfo> {\n const { version, force = false, onProgress = () => {} } = options;\n\n const binaryPath = this.getBinaryPath();\n\n // Check if already installed\n if (!force && existsSync(binaryPath)) {\n const info = await this.getBinaryInfo();\n if (info.ready) {\n onProgress({ phase: 'installing', message: `Binary already installed at ${binaryPath}` });\n return info;\n }\n }\n\n // Ensure install directory exists\n if (!existsSync(this.installDir)) {\n mkdirSync(this.installDir, { recursive: true });\n }\n\n // Resolve release tag\n onProgress({ phase: 'fetching', message: 'Resolving release tag...' });\n const tag = this.normalizeTag(version || DEFAULT_FIBER_VERSION);\n\n onProgress({ phase: 'fetching', message: `Found release: ${tag}` });\n\n // Build asset candidates\n const candidates = this.buildAssetCandidates(tag);\n\n let response: Response | undefined;\n let selected: AssetCandidate | undefined;\n const attempted: string[] = [];\n\n for (const candidate of candidates) {\n onProgress({\n phase: 'downloading',\n message: `Downloading ${candidate.name} from ${candidate.url}...`,\n percent: 0,\n });\n attempted.push(candidate.name);\n const candidateResponse = await fetch(candidate.url, {\n headers: { 'User-Agent': 'fiber-pay' },\n });\n\n if (candidateResponse.ok) {\n response = candidateResponse;\n selected = candidate;\n break;\n }\n }\n\n if (!response || !selected) {\n const attemptedUrls = candidates.map((candidate) => candidate.url).join(', ');\n throw new Error(`Download failed. Tried: ${attempted.join(', ')}. URLs: ${attemptedUrls}`);\n }\n\n onProgress({\n phase: 'downloading',\n message: `Using ${selected.name} (${selected.url})`,\n });\n\n if (selected.usesRosetta) {\n onProgress({\n phase: 'downloading',\n message: `No ARM64 binary available, using x86_64 version with Rosetta 2...`,\n });\n\n await this.ensureRosettaAvailable();\n\n onProgress({\n phase: 'downloading',\n message: `Rosetta 2 available, continuing with x86_64 fallback binary...`,\n });\n }\n\n const contentLength = parseInt(response.headers.get('content-length') || '0', 10);\n\n // Stream download with progress\n const body = response.body;\n if (!body) {\n throw new Error('No response body');\n }\n\n let downloaded = 0;\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n chunks.push(value);\n downloaded += value.length;\n\n if (contentLength > 0) {\n const percent = Math.round((downloaded / contentLength) * 100);\n onProgress({\n phase: 'downloading',\n message: `Downloading... ${percent}%`,\n percent,\n });\n }\n }\n\n const buffer = Buffer.concat(chunks);\n\n // Handle different archive formats\n onProgress({ phase: 'extracting', message: 'Extracting binary...' });\n\n if (selected.name.endsWith('.tar.gz') || selected.name.endsWith('.tgz')) {\n await this.extractTarGz(buffer, binaryPath);\n } else if (selected.name.endsWith('.zip')) {\n await this.extractZip(buffer, binaryPath);\n } else {\n // Direct binary\n const { writeFile } = await import('node:fs/promises');\n await writeFile(binaryPath, buffer);\n }\n\n // Make executable (Unix)\n const { platform } = this.getPlatformInfo();\n if (platform !== 'win32') {\n chmodSync(binaryPath, 0o755);\n }\n\n onProgress({ phase: 'installing', message: `Installed to ${binaryPath}` });\n\n return this.getBinaryInfo();\n }\n\n /**\n * Extract tar.gz archive\n */\n private async extractTarGz(buffer: Buffer, targetPath: string): Promise<void> {\n const { writeFile, readdir, rename, rm } = await import('node:fs/promises');\n const tempDir = `${targetPath}.extract`;\n\n // Create temp directory\n if (!existsSync(tempDir)) {\n mkdirSync(tempDir, { recursive: true });\n }\n\n // Write archive to temp file\n const archivePath = `${tempDir}/archive.tar.gz`;\n await writeFile(archivePath, buffer);\n\n // Extract using tar command\n try {\n await execAsync(`tar -xzf \"${archivePath}\" -C \"${tempDir}\"`);\n } catch (primaryError) {\n // Fallback: use Node's built-in zlib to avoid external `gunzip` dependency\n try {\n const { gunzipSync } = await import('node:zlib');\n const tarPath = `${tempDir}/archive.tar`;\n const tarBuffer = gunzipSync(buffer);\n await writeFile(tarPath, tarBuffer);\n await execAsync(`tar -xf \"${tarPath}\" -C \"${tempDir}\"`);\n } catch (fallbackError) {\n const primaryMessage =\n primaryError instanceof Error ? primaryError.message : String(primaryError);\n const fallbackMessage =\n fallbackError instanceof Error ? fallbackError.message : String(fallbackError);\n throw new Error(\n `Failed to extract tar.gz archive. Primary: ${primaryMessage}. Fallback: ${fallbackMessage}`,\n );\n }\n }\n\n // Find the binary in extracted files\n const files = await readdir(tempDir, { recursive: true });\n const binaryFile = this.findBinaryInExtractedFiles(files, 'fnn');\n\n if (binaryFile) {\n const sourcePath = join(tempDir, String(binaryFile));\n await rename(sourcePath, targetPath);\n } else {\n // If no fnn found, maybe the archive contains a single binary\n const extractedFiles = await readdir(tempDir);\n const possibleBinary = extractedFiles.find(\n (f) => f !== 'archive.tar.gz' && !f.startsWith('.'),\n );\n if (possibleBinary) {\n await rename(join(tempDir, possibleBinary), targetPath);\n }\n }\n\n // Also extract fnn-migrate if present in the archive\n const migrateFile = this.findBinaryInExtractedFiles(files, 'fnn-migrate');\n\n if (migrateFile) {\n const migrateSourcePath = join(tempDir, String(migrateFile));\n const migrateTargetPath = this.getMigrateBinaryPath();\n try {\n // Proactively remove existing fnn-migrate so rename doesn't fail\n if (existsSync(migrateTargetPath)) {\n try {\n unlinkSync(migrateTargetPath);\n } catch {\n // If we can't remove the existing file, the rename will likely fail below\n }\n }\n await rename(migrateSourcePath, migrateTargetPath);\n const { platform } = this.getPlatformInfo();\n if (platform !== 'win32') {\n chmodSync(migrateTargetPath, 0o755);\n }\n } catch (error) {\n // fnn-migrate is optional; don't fail the main install, but warn\n const message = error instanceof Error ? error.message : String(error);\n console.warn(\n `Warning: failed to install fnn-migrate helper. Migrations may be unavailable or stale. Error: ${message}`,\n );\n }\n }\n\n // Cleanup temp directory\n await rm(tempDir, { recursive: true, force: true });\n }\n\n /**\n * Extract zip archive (primarily for Windows)\n */\n private async extractZip(buffer: Buffer, targetPath: string): Promise<void> {\n const { writeFile, readdir, rename, rm } = await import('node:fs/promises');\n const tempDir = `${targetPath}.extract`;\n\n if (!existsSync(tempDir)) {\n mkdirSync(tempDir, { recursive: true });\n }\n\n const archivePath = `${tempDir}/archive.zip`;\n await writeFile(archivePath, buffer);\n\n // Extract using unzip command\n const { platform } = this.getPlatformInfo();\n if (platform === 'win32') {\n await execAsync(\n `powershell -command \"Expand-Archive -Path '${archivePath}' -DestinationPath '${tempDir}'\"`,\n );\n } else {\n await execAsync(`unzip -o \"${archivePath}\" -d \"${tempDir}\"`);\n }\n\n // Find and move the binary\n const files = await readdir(tempDir, { recursive: true });\n const binaryFile = this.findBinaryInExtractedFiles(files, 'fnn');\n\n if (binaryFile) {\n await rename(join(tempDir, String(binaryFile)), targetPath);\n }\n\n // Also extract fnn-migrate if present\n const migrateFile = this.findBinaryInExtractedFiles(files, 'fnn-migrate');\n\n if (migrateFile) {\n const migrateTargetPath = this.getMigrateBinaryPath();\n try {\n // Proactively remove existing fnn-migrate so rename doesn't fail\n if (existsSync(migrateTargetPath)) {\n try {\n unlinkSync(migrateTargetPath);\n } catch {\n // If we can't remove the existing file, the rename will likely fail below\n }\n }\n await rename(join(tempDir, String(migrateFile)), migrateTargetPath);\n const { platform } = this.getPlatformInfo();\n if (platform !== 'win32') {\n chmodSync(migrateTargetPath, 0o755);\n }\n } catch (error) {\n // fnn-migrate is optional; don't fail the main install, but warn\n const message = error instanceof Error ? error.message : String(error);\n console.warn(\n `Warning: failed to install fnn-migrate helper. Migrations may be unavailable or stale. Error: ${message}`,\n );\n }\n }\n\n await rm(tempDir, { recursive: true, force: true });\n }\n\n /**\n * Remove the installed binary\n */\n async uninstall(): Promise<void> {\n const binaryPath = this.getBinaryPath();\n if (existsSync(binaryPath)) {\n unlinkSync(binaryPath);\n }\n }\n\n /**\n * Find a named binary in a list of extracted file paths.\n */\n private findBinaryInExtractedFiles(\n files: (string | Buffer)[],\n binaryName: 'fnn' | 'fnn-migrate',\n ): string | Buffer | undefined {\n return files.find((f) => {\n const name = String(f);\n return (\n name.endsWith(`/${binaryName}`) ||\n name === binaryName ||\n name.endsWith(`\\\\${binaryName}`) ||\n name.endsWith(`${binaryName}.exe`)\n );\n });\n }\n}\n\n// =============================================================================\n// Convenience Functions\n// =============================================================================\n\n/**\n * Download the Fiber binary to the default location\n */\nexport async function downloadFiberBinary(options: DownloadOptions = {}): Promise<BinaryInfo> {\n const manager = new BinaryManager(options.installDir);\n return manager.download(options);\n}\n\n/**\n * Get information about the installed binary\n */\nexport async function getFiberBinaryInfo(installDir?: string): Promise<BinaryInfo> {\n const manager = new BinaryManager(installDir);\n return manager.getBinaryInfo();\n}\n\n/**\n * Ensure the Fiber binary is available, downloading if necessary.\n * If the binary exists but its version does not match the requested\n * (or default) version, it will be re-downloaded.\n */\nexport async function ensureFiberBinary(options: DownloadOptions = {}): Promise<string> {\n const manager = new BinaryManager(options.installDir);\n const info = await manager.getBinaryInfo();\n let downloadOptions = options;\n\n if (info.ready) {\n const wantedTag = manager.normalizeTag(options.version || DEFAULT_FIBER_VERSION);\n const wantedVersion = wantedTag.startsWith('v') ? wantedTag.slice(1) : wantedTag;\n if (info.version === wantedVersion) {\n return info.path;\n }\n // Version mismatch — force re-download.\n downloadOptions = { ...options, force: true };\n }\n\n const downloaded = await manager.download(downloadOptions);\n return downloaded.path;\n}\n\n/**\n * Get the default binary path\n */\nexport function getDefaultBinaryPath(): string {\n const manager = new BinaryManager();\n return manager.getBinaryPath();\n}\n","/**\n * Migration Manager\n * Handles Fiber node database migration when upgrading between versions.\n *\n * Uses the `fnn-migrate` binary shipped in Fiber release archives to migrate\n * the on-disk store format so that it is compatible with a newer `fnn` binary.\n */\n\nimport { execFile } from 'node:child_process';\nimport { cpSync, existsSync, mkdirSync, renameSync, rmSync, statSync } from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface MigrationCheckResult {\n /** Whether migration is needed */\n needed: boolean;\n /** Whether the store is valid (parseable) */\n valid: boolean;\n /** Whether this fnn-migrate version does not support pre-check mode */\n precheckUnsupported: boolean;\n /** Human-readable status message */\n message: string;\n /** Path to the store that was checked */\n storePath: string;\n}\n\nexport interface MigrationResult {\n /** Whether migration succeeded */\n success: boolean;\n /** Path to backup directory (if created) */\n backupPath?: string;\n /** Human-readable message */\n message: string;\n /** Detailed output from fnn-migrate */\n output?: string;\n}\n\nexport interface MigrationOptions {\n /** Path to the fiber store directory (typically `<dataDir>/fiber/store`) */\n storePath: string;\n /** Create a backup before migrating (default: true) */\n backup?: boolean;\n /** Directory to place backups in (default: sibling of storePath) */\n backupDir?: string;\n /**\n * Force migration attempt even when pre-check reports incompatible data.\n * Use carefully: migration command may still fail and store may require\n * manual recovery; backup is strongly recommended.\n */\n force?: boolean;\n}\n\n// =============================================================================\n// Migration Manager\n// =============================================================================\n\nexport class MigrationManager {\n private migrateBinaryPath: string;\n private helpTextCache: string | null = null;\n\n constructor(migrateBinaryPath: string) {\n this.migrateBinaryPath = migrateBinaryPath;\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n /**\n * Check whether the store needs migration or is incompatible.\n *\n * Runs `fnn-migrate` compatibility check when supported by the installed\n * migrate helper.\n */\n async check(storePath: string): Promise<MigrationCheckResult> {\n this.ensureBinaryExists();\n\n if (!existsSync(storePath)) {\n return {\n needed: false,\n valid: true,\n precheckUnsupported: false,\n message: 'Store does not exist yet — no migration needed.',\n storePath,\n };\n }\n\n const helpText = await this.getHelpText();\n const supportsCheckValidate = helpText.includes('--check-validate');\n\n // Newer fnn-migrate (v0.8.x) removed check mode; in that case we skip\n // compatibility pre-check instead of hard-failing startup/upgrade.\n if (!supportsCheckValidate) {\n return {\n needed: false,\n valid: true,\n precheckUnsupported: true,\n message:\n 'Store pre-check is not supported by this fnn-migrate version; skipping compatibility check.',\n storePath,\n };\n }\n\n try {\n const { stdout, stderr } = await this.execWithStoreTargetArgs(storePath, [\n '--check-validate',\n ]);\n const output = `${stdout}\\n${stderr}`.trim();\n if (output.includes('validate success')) {\n return {\n needed: false,\n valid: true,\n precheckUnsupported: false,\n message: 'Store is up-to-date, no migration needed.',\n storePath,\n };\n }\n return {\n needed: false,\n valid: true,\n precheckUnsupported: false,\n message: output || 'Store validation passed.',\n storePath,\n };\n } catch (error) {\n const stderr = this.extractStderr(error);\n const isIncompatible =\n stderr.includes('incompatible database') || stderr.includes('need to upgrade');\n const needsMigration =\n stderr.includes('need to run database migration') || stderr.includes('need to migrate');\n const needsCleanStart =\n stderr.includes('shutdown all channels') || stderr.includes('shutdown all old channels');\n\n if (needsCleanStart) {\n return {\n needed: true,\n valid: false,\n precheckUnsupported: false,\n message:\n 'Store requires a breaking migration that cannot be auto-migrated. ' +\n 'You need to:\\n' +\n ' 1. Start the OLD version of fnn\\n' +\n ' 2. Close all channels (cooperative or forced)\\n' +\n ' 3. Stop the old node\\n' +\n ' 4. Remove the store directory\\n' +\n ' 5. Start the new fnn version with a fresh database\\n\\n' +\n 'See: https://github.com/nervosnetwork/fiber/wiki/Fiber-Breaking-Change-Migration-Guide',\n storePath,\n };\n }\n\n if (needsMigration) {\n return {\n needed: true,\n valid: true,\n precheckUnsupported: false,\n message: 'Store needs migration. Run `fiber-pay node upgrade` to migrate.',\n storePath,\n };\n }\n\n if (isIncompatible) {\n return {\n needed: true,\n valid: false,\n precheckUnsupported: false,\n message: `Store is incompatible: ${stderr}`,\n storePath,\n };\n }\n\n return {\n needed: true,\n valid: false,\n precheckUnsupported: false,\n message: `Store validation failed: ${stderr}`,\n storePath,\n };\n }\n }\n\n /**\n * Create a timestamped backup of the store directory.\n *\n * @returns The path to the created backup directory.\n */\n backup(storePath: string, backupDir?: string): string {\n if (!existsSync(storePath)) {\n throw new Error(`Store path does not exist: ${storePath}`);\n }\n\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n const storeName = basename(storePath);\n const targetDir = backupDir || dirname(storePath);\n const backupPath = join(targetDir, `${storeName}.bak-${timestamp}`);\n\n mkdirSync(backupPath, { recursive: true });\n cpSync(storePath, backupPath, { recursive: true });\n\n return backupPath;\n }\n\n /**\n * Run the database migration.\n *\n * Optionally creates a backup first. Uses `--skip-confirm` to avoid\n * interactive prompts.\n */\n async migrate(options: MigrationOptions): Promise<MigrationResult> {\n const { storePath, backup: doBackup = true, backupDir, force = false } = options;\n\n this.ensureBinaryExists();\n\n if (!existsSync(storePath)) {\n return {\n success: true,\n message: 'Store does not exist — nothing to migrate.',\n };\n }\n\n // Pre-flight check\n const checkResult = await this.check(storePath);\n const precheckUnsupported = checkResult.precheckUnsupported;\n\n if (!checkResult.needed && !(force && precheckUnsupported)) {\n return {\n success: true,\n message: checkResult.message,\n };\n }\n\n if (!checkResult.valid && !force) {\n return {\n success: false,\n message: checkResult.message,\n };\n }\n\n // Backup\n let backupPath: string | undefined;\n if (doBackup) {\n try {\n backupPath = this.backup(storePath, backupDir);\n } catch (backupError) {\n const msg = backupError instanceof Error ? backupError.message : String(backupError);\n return {\n success: false,\n message: `Failed to create backup before migration: ${msg}`,\n };\n }\n }\n\n // Run migration\n try {\n const { stdout, stderr } = await this.execMigrateCommand(storePath);\n const output = `${stdout}\\n${stderr}`.trim();\n\n if (output.includes('migrated successfully') || output.includes('db migrated')) {\n return {\n success: true,\n backupPath,\n message: 'Migration completed successfully.',\n output,\n };\n }\n\n if (output.toLowerCase().includes('no need to migrate')) {\n return {\n success: true,\n backupPath,\n message: 'Store is already up-to-date; no migration needed.',\n output,\n };\n }\n\n // Command exited 0 but no recognized success message — treat as failure to be safe\n let ambiguousMessage = `Migration command finished without errors, but the expected success message was not found. Output: ${output}`;\n if (backupPath) {\n ambiguousMessage += `\\n\\nA backup was created at: ${backupPath}\\nTo roll back, delete the current store at \"${storePath}\" and restore the backup from that path.`;\n }\n return {\n success: false,\n backupPath,\n message: ambiguousMessage,\n output,\n };\n } catch (error) {\n const stderr = this.extractStderr(error);\n\n // Offer rollback information\n let message = `Migration failed: ${stderr}`;\n if (backupPath) {\n message += `\\n\\nA backup was created at: ${backupPath}\\nTo roll back, delete the current store at \"${storePath}\" and restore the backup from that path.`;\n }\n\n return {\n success: false,\n backupPath,\n message,\n output: stderr,\n };\n }\n }\n\n /**\n * Rollback a migration by restoring a backup.\n */\n rollback(storePath: string, backupPath: string): void {\n if (!existsSync(backupPath)) {\n throw new Error(`Backup path does not exist: ${backupPath}`);\n }\n\n // Remove the (potentially corrupted) current store\n if (existsSync(storePath)) {\n rmSync(storePath, { recursive: true, force: true });\n }\n\n // Restore from backup\n renameSync(backupPath, storePath);\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Resolve the store path from a data directory.\n *\n * The fiber node stores its database at `<dataDir>/fiber/store`.\n */\n static resolveStorePath(dataDir: string): string {\n return join(dataDir, 'fiber', 'store');\n }\n\n /**\n * Check if the store directory exists and is a directory.\n */\n static storeExists(dataDir: string): boolean {\n const storePath = MigrationManager.resolveStorePath(dataDir);\n if (!existsSync(storePath)) return false;\n try {\n const stats = statSync(storePath);\n return stats.isDirectory();\n } catch {\n return false;\n }\n }\n\n private ensureBinaryExists(): void {\n if (!existsSync(this.migrateBinaryPath)) {\n throw new Error(\n `fnn-migrate binary not found at: ${this.migrateBinaryPath}\\n` +\n 'This binary is required for database migration.\\n' +\n 'Re-download the Fiber binary with: fiber-pay binary download --force',\n );\n }\n }\n\n private async getHelpText(): Promise<string> {\n if (this.helpTextCache !== null) {\n return this.helpTextCache;\n }\n\n try {\n const { stdout, stderr } = await execFileAsync(this.migrateBinaryPath, ['--help']);\n this.helpTextCache = `${stdout}\\n${stderr}`;\n return this.helpTextCache;\n } catch (error) {\n // If help invocation itself fails, treat as unknown capability and rely on\n // argument-shape fallback at execution time.\n this.helpTextCache = this.extractStderr(error);\n return this.helpTextCache;\n }\n }\n\n private async resolveTargetArgCandidates(storePath: string): Promise<string[][]> {\n const helpText = await this.getHelpText();\n const fiberDataDir = dirname(storePath);\n const prefersDirArg = helpText.includes('--dir');\n\n if (prefersDirArg) {\n return [\n ['--dir', fiberDataDir],\n ['-p', storePath],\n ];\n }\n\n return [\n ['-p', storePath],\n ['--dir', fiberDataDir],\n ];\n }\n\n private isArgShapeError(message: string): boolean {\n const lower = message.toLowerCase();\n return (\n lower.includes('unexpected argument') ||\n lower.includes('found argument') ||\n lower.includes('unknown option') ||\n lower.includes('invalid option') ||\n lower.includes('usage: fnn-migrate')\n );\n }\n\n private async execWithStoreTargetArgs(\n storePath: string,\n extraArgs: string[],\n ): Promise<{ stdout: string; stderr: string }> {\n const candidates = await this.resolveTargetArgCandidates(storePath);\n let lastError: unknown = new Error('No valid fnn-migrate target argument style found.');\n\n for (const targetArgs of candidates) {\n try {\n return await execFileAsync(this.migrateBinaryPath, [...targetArgs, ...extraArgs]);\n } catch (error) {\n const msg = this.extractStderr(error);\n if (this.isArgShapeError(msg)) {\n lastError = error;\n continue;\n }\n throw error;\n }\n }\n\n throw lastError;\n }\n\n private async execMigrateCommand(storePath: string): Promise<{ stdout: string; stderr: string }> {\n try {\n return await this.execWithStoreTargetArgs(storePath, ['--skip-confirm']);\n } catch (error) {\n const msg = this.extractStderr(error);\n if (!this.isArgShapeError(msg) || !msg.includes('--skip-confirm')) {\n throw error;\n }\n }\n\n return this.execWithStoreTargetArgs(storePath, ['-s']);\n }\n\n private extractStderr(error: unknown): string {\n if (error && typeof error === 'object') {\n const e = error as { stderr?: string; stdout?: string; message?: string };\n return (e.stderr || e.stdout || e.message || String(error)).trim();\n }\n return String(error);\n }\n}\n","/**\n * Process Manager\n * Manages the lifecycle of the Fiber Network Node (fnn) binary\n */\n\nimport { type ChildProcess, spawn } from 'node:child_process';\nimport { EventEmitter } from 'node:events';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport * as yaml from './yaml.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface FiberNodeConfig {\n /** Path to the fnn binary */\n binaryPath: string;\n /** Base directory for data storage */\n dataDir: string;\n /** Path to the config file (optional - will use built-in testnet config if not provided) */\n configFilePath?: string;\n /** Fiber P2P listening address */\n fiberListeningAddr?: string;\n /** Fiber node name */\n nodeName?: string;\n /** Bootstrap node addresses */\n bootnodeAddrs?: string[];\n /** CKB RPC URL */\n ckbRpcUrl?: string;\n /** RPC listening address */\n rpcListeningAddr?: string;\n /** Chain configuration (mainnet, testnet, or file path) */\n chain?: 'mainnet' | 'testnet' | string;\n /** Key encryption password */\n keyPassword?: string;\n /** Log level */\n logLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error';\n /** UDT whitelist */\n udtWhitelist?: Array<{\n name: string;\n script: {\n code_hash: string;\n hash_type: 'type' | 'data' | 'data1' | 'data2';\n args: string;\n };\n }>;\n}\n\nexport interface ProcessManagerEvents {\n started: () => void;\n stopped: (code: number | null, signal: NodeJS.Signals | null) => void;\n error: (error: Error) => void;\n stdout: (data: string) => void;\n stderr: (data: string) => void;\n ready: () => void;\n}\n\nexport type ProcessState = 'stopped' | 'starting' | 'running' | 'stopping';\n\nconst DEFAULT_TESTNET_FIBER_CONFIG = {\n listening_addr: '/ip4/0.0.0.0/tcp/8228',\n bootnode_addrs: [\n '/ip4/54.179.226.154/tcp/8228/p2p/Qmes1EBD4yNo9Ywkfe6eRw9tG1nVNGLDmMud1xJMsoYFKy',\n '/ip4/16.163.7.105/tcp/8228/p2p/QmdyQWjPtbK4NWWsvy8s69NGJaQULwgeQDT5ZpNDrTNaeV',\n ],\n announce_listening_addr: true,\n chain: 'testnet',\n scripts: [\n {\n name: 'FundingLock',\n script: {\n code_hash: '0x6c67887fe201ee0c7853f1682c0b77c0e6214044c156c7558269390a8afa6d7c',\n hash_type: 'type',\n args: '0x',\n },\n cell_deps: [\n {\n type_id: {\n code_hash: '0x00000000000000000000000000000000000000000000000000545950455f4944',\n hash_type: 'type',\n args: '0x3cb7c0304fe53f75bb5727e2484d0beae4bd99d979813c6fc97c3cca569f10f6',\n },\n },\n {\n cell_dep: {\n out_point: {\n tx_hash: '0x12c569a258dd9c5bd99f632bb8314b1263b90921ba31496467580d6b79dd14a7',\n index: '0x0',\n },\n dep_type: 'code',\n },\n },\n ],\n },\n {\n name: 'CommitmentLock',\n script: {\n code_hash: '0x740dee83f87c6f309824d8fd3fbdd3c8380ee6fc9acc90b1a748438afcdf81d8',\n hash_type: 'type',\n args: '0x',\n },\n cell_deps: [\n {\n type_id: {\n code_hash: '0x00000000000000000000000000000000000000000000000000545950455f4944',\n hash_type: 'type',\n args: '0xf7e458887495cf70dd30d1543cad47dc1dfe9d874177bf19291e4db478d5751b',\n },\n },\n {\n cell_dep: {\n out_point: {\n tx_hash: '0x12c569a258dd9c5bd99f632bb8314b1263b90921ba31496467580d6b79dd14a7',\n index: '0x0',\n },\n dep_type: 'code',\n },\n },\n ],\n },\n ],\n} as const;\n\n// =============================================================================\n// Process Manager\n// =============================================================================\n\nexport class ProcessManager extends EventEmitter {\n private config: FiberNodeConfig;\n private process: ChildProcess | null = null;\n private state: ProcessState = 'stopped';\n private configPath: string;\n private stdoutBuffer: string[] = [];\n private stderrBuffer: string[] = [];\n private maxBufferSize = 1000;\n\n constructor(config: FiberNodeConfig) {\n super();\n this.config = config;\n this.configPath = join(config.dataDir, 'config.yml');\n }\n\n /**\n * Get current process state\n */\n getState(): ProcessState {\n return this.state;\n }\n\n /**\n * Check if the process is running\n */\n isRunning(): boolean {\n return this.state === 'running' || this.state === 'starting';\n }\n\n /**\n * Start the Fiber node\n */\n async start(): Promise<void> {\n if (this.isRunning()) {\n throw new Error('Node is already running');\n }\n\n this.state = 'starting';\n\n // Ensure data directory exists\n if (!existsSync(this.config.dataDir)) {\n mkdirSync(this.config.dataDir, { recursive: true });\n }\n\n // Copy or generate config file\n await this.ensureConfigFile();\n\n // Build environment variables\n const env: Record<string, string> = {\n ...process.env,\n RUST_LOG: this.config.logLevel || 'info',\n };\n\n // FIBER_SECRET_KEY_PASSWORD is always required by the fiber node\n // Use the provided password or generate a default one\n env.FIBER_SECRET_KEY_PASSWORD = this.config.keyPassword || 'fiber-pay-default-key';\n\n // Spawn the process\n const args = ['-c', this.configPath, '-d', this.config.dataDir];\n\n this.process = spawn(this.config.binaryPath, args, {\n env,\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: false,\n });\n\n // Handle stdout\n this.process.stdout?.on('data', (data: Buffer) => {\n const text = data.toString();\n this.stdoutBuffer.push(text);\n if (this.stdoutBuffer.length > this.maxBufferSize) {\n this.stdoutBuffer.shift();\n }\n this.emit('stdout', text);\n\n // Check for ready signal\n if (text.includes('RPC server started') || text.includes('listening on')) {\n if (this.state === 'starting') {\n this.state = 'running';\n this.emit('ready');\n }\n }\n });\n\n // Handle stderr\n this.process.stderr?.on('data', (data: Buffer) => {\n const text = data.toString();\n this.stderrBuffer.push(text);\n if (this.stderrBuffer.length > this.maxBufferSize) {\n this.stderrBuffer.shift();\n }\n this.emit('stderr', text);\n });\n\n // Handle process exit\n this.process.on('exit', (code, signal) => {\n this.state = 'stopped';\n this.process = null;\n this.emit('stopped', code, signal);\n });\n\n // Handle process error\n this.process.on('error', (error) => {\n this.state = 'stopped';\n this.process = null;\n this.emit('error', error);\n });\n\n this.emit('started');\n\n // Wait a bit for the process to initialize\n await new Promise((resolve) => setTimeout(resolve, 500));\n\n // If process died immediately, throw error\n // State may have changed due to async event handlers\n if ((this.state as ProcessState) === 'stopped') {\n throw new Error('Process exited immediately. Check logs.');\n }\n }\n\n /**\n * Stop the Fiber node\n */\n async stop(timeout = 10000): Promise<void> {\n if (!this.process || this.state === 'stopped') {\n return;\n }\n\n this.state = 'stopping';\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n // Force kill if graceful shutdown fails\n this.process?.kill('SIGKILL');\n }, timeout);\n\n this.once('stopped', () => {\n clearTimeout(timer);\n resolve();\n });\n\n this.once('error', (error) => {\n clearTimeout(timer);\n reject(error);\n });\n\n // Send SIGTERM for graceful shutdown\n this.process?.kill('SIGTERM');\n });\n }\n\n /**\n * Restart the Fiber node\n */\n async restart(): Promise<void> {\n await this.stop();\n await this.start();\n }\n\n /**\n * Get recent stdout output\n */\n getStdout(lines?: number): string[] {\n if (lines) {\n return this.stdoutBuffer.slice(-lines);\n }\n return [...this.stdoutBuffer];\n }\n\n /**\n * Get recent stderr output\n */\n getStderr(lines?: number): string[] {\n if (lines) {\n return this.stderrBuffer.slice(-lines);\n }\n return [...this.stderrBuffer];\n }\n\n /**\n * Get the RPC URL for this node\n */\n getRpcUrl(): string {\n const addr = this.config.rpcListeningAddr || '127.0.0.1:8227';\n return `http://${addr}`;\n }\n\n /**\n * Wait for the node to be ready\n */\n waitForReady(timeout = 60000): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.state === 'running') {\n resolve();\n return;\n }\n\n const timer = setTimeout(() => {\n this.off('ready', onReady);\n this.off('stopped', onStopped);\n reject(new Error('Timeout waiting for node to be ready'));\n }, timeout);\n\n const onReady = () => {\n clearTimeout(timer);\n this.off('stopped', onStopped);\n resolve();\n };\n\n const onStopped = () => {\n clearTimeout(timer);\n this.off('ready', onReady);\n reject(new Error('Node stopped while waiting for ready'));\n };\n\n this.once('ready', onReady);\n this.once('stopped', onStopped);\n });\n }\n\n /**\n * Ensure the config file exists (copy from source or generate)\n */\n private async ensureConfigFile(): Promise<void> {\n const configDir = dirname(this.configPath);\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n // If a config file path is provided, copy it\n if (this.config.configFilePath && existsSync(this.config.configFilePath)) {\n // Copy the config file to the data directory\n const sourceContent = readFileSync(this.config.configFilePath, 'utf-8');\n writeFileSync(this.configPath, sourceContent);\n return;\n }\n\n // Otherwise, generate a basic config file\n this.generateConfigFile();\n }\n\n /**\n * Generate the config file (fallback when no source config provided)\n */\n private generateConfigFile(): void {\n const chain = this.config.chain || 'testnet';\n const useDefaultTestnetConfig = chain === 'testnet';\n const config: Record<string, unknown> = {\n fiber: useDefaultTestnetConfig\n ? { ...DEFAULT_TESTNET_FIBER_CONFIG }\n : {\n listening_addr: this.config.fiberListeningAddr || '/ip4/127.0.0.1/tcp/8228',\n announce_listening_addr: true,\n chain,\n },\n rpc: {\n listening_addr: this.config.rpcListeningAddr || '127.0.0.1:8227',\n },\n ckb: {\n rpc_url: this.config.ckbRpcUrl || 'https://testnet.ckbapp.dev/',\n },\n services: ['fiber', 'rpc', 'ckb'],\n };\n\n if (this.config.nodeName) {\n (config.fiber as Record<string, unknown>).announced_node_name = this.config.nodeName;\n }\n\n if (this.config.bootnodeAddrs?.length) {\n (config.fiber as Record<string, unknown>).bootnode_addrs = this.config.bootnodeAddrs;\n }\n\n if (this.config.udtWhitelist?.length) {\n (config.ckb as Record<string, unknown>).udt_whitelist = this.config.udtWhitelist;\n }\n\n const configDir = dirname(this.configPath);\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n writeFileSync(this.configPath, yaml.stringify(config));\n }\n}\n","/**\n * Simple YAML serializer\n * Minimal implementation for config file generation\n */\n\nexport function stringify(obj: unknown, indent = 0): string {\n const spaces = ' '.repeat(indent);\n\n if (obj === null || obj === undefined) {\n return 'null';\n }\n\n if (typeof obj === 'string') {\n // Quote strings that need it\n if (\n obj.includes(':') ||\n obj.includes('#') ||\n obj.includes('\\n') ||\n obj.startsWith(' ') ||\n obj.endsWith(' ') ||\n obj === '' ||\n obj === 'true' ||\n obj === 'false' ||\n !Number.isNaN(Number(obj))\n ) {\n return JSON.stringify(obj);\n }\n return obj;\n }\n\n if (typeof obj === 'number' || typeof obj === 'boolean') {\n return String(obj);\n }\n\n if (Array.isArray(obj)) {\n if (obj.length === 0) {\n return '[]';\n }\n return obj\n .map((item) => {\n const value = stringify(item, indent + 1);\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n // Multi-line object in array\n const lines = value.split('\\n');\n return `${spaces}- ${lines[0]}\\n${lines\n .slice(1)\n .map((l) => `${spaces} ${l}`)\n .join('\\n')}`;\n }\n return `${spaces}- ${value}`;\n })\n .join('\\n');\n }\n\n if (typeof obj === 'object') {\n const entries = Object.entries(obj as Record<string, unknown>);\n if (entries.length === 0) {\n return '{}';\n }\n return entries\n .map(([key, value]) => {\n const valueStr = stringify(value, indent + 1);\n if (\n typeof value === 'object' &&\n value !== null &&\n !(Array.isArray(value) && value.length === 0) &&\n !(typeof value === 'object' && Object.keys(value).length === 0)\n ) {\n return `${spaces}${key}:\\n${valueStr}`;\n }\n return `${spaces}${key}: ${valueStr}`;\n })\n .join('\\n');\n }\n\n return String(obj);\n}\n\nexport function parse(yaml: string): unknown {\n // Basic YAML parsing - for production use a proper library\n const lines = yaml.split('\\n');\n const result: Record<string, unknown> = {};\n const stack: Array<{ indent: number; obj: Record<string, unknown>; key?: string }> = [\n { indent: -1, obj: result },\n ];\n\n for (const line of lines) {\n // Skip empty lines and comments\n if (!line.trim() || line.trim().startsWith('#')) {\n continue;\n }\n\n const indent = line.search(/\\S/);\n const content = line.trim();\n\n // Handle key: value\n const colonIndex = content.indexOf(':');\n if (colonIndex > 0) {\n const key = content.slice(0, colonIndex).trim();\n const value = content.slice(colonIndex + 1).trim();\n\n // Pop stack to correct level\n while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {\n stack.pop();\n }\n\n const parent = stack[stack.length - 1].obj;\n\n if (value === '' || value === '|' || value === '>') {\n // Nested object\n const newObj: Record<string, unknown> = {};\n parent[key] = newObj;\n stack.push({ indent, obj: newObj, key });\n } else {\n // Primitive value\n parent[key] = parseValue(value);\n }\n }\n }\n\n return result;\n}\n\nfunction parseValue(value: string): unknown {\n // Remove quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n\n // Boolean\n if (value === 'true') return true;\n if (value === 'false') return false;\n\n // Null\n if (value === 'null' || value === '~') return null;\n\n // Number\n const num = Number(value);\n if (!Number.isNaN(num)) return num;\n\n // Array (inline)\n if (value.startsWith('[') && value.endsWith(']')) {\n return JSON.parse(value);\n }\n\n return value;\n}\n","/**\n * Key Manager\n * Handles generation, storage, and encryption of Fiber node keys\n * Keys are isolated from LLM context for security\n */\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { KeyConfig, KeyInfo } from '@fiber-pay/sdk';\nimport { decryptKey, derivePublicKey, generatePrivateKey, isEncryptedKey } from '@fiber-pay/sdk';\n\n// =============================================================================\n// Key Manager\n// =============================================================================\n\nexport class KeyManager {\n private config: KeyConfig;\n private fiberKeyPath: string;\n private ckbKeyPath: string;\n\n constructor(config: KeyConfig) {\n this.config = config;\n this.fiberKeyPath = join(config.baseDir, 'fiber', 'sk');\n this.ckbKeyPath = join(config.baseDir, 'ckb', 'key');\n }\n\n /**\n * Initialize keys - generate if they don't exist and autoGenerate is true\n */\n async initialize(): Promise<{ fiber: KeyInfo; ckb: KeyInfo }> {\n const fiberExists = existsSync(this.fiberKeyPath);\n const ckbExists = existsSync(this.ckbKeyPath);\n\n if (!fiberExists || !ckbExists) {\n if (!this.config.autoGenerate) {\n throw new Error(\n `Keys not found and autoGenerate is disabled. ` +\n `Missing: ${[!fiberExists && 'fiber', !ckbExists && 'ckb'].filter(Boolean).join(', ')}`,\n );\n }\n }\n\n // Generate missing keys\n if (!fiberExists) {\n await this.generateKey('fiber');\n }\n if (!ckbExists) {\n await this.generateKey('ckb');\n }\n\n return {\n fiber: await this.getKeyInfo('fiber'),\n ckb: await this.getKeyInfo('ckb'),\n };\n }\n\n /**\n * Generate a new key\n */\n async generateKey(type: 'fiber' | 'ckb'): Promise<KeyInfo> {\n const keyPath = type === 'fiber' ? this.fiberKeyPath : this.ckbKeyPath;\n const keyDir = dirname(keyPath);\n\n // Create directory if it doesn't exist\n if (!existsSync(keyDir)) {\n mkdirSync(keyDir, { recursive: true });\n }\n\n // Generate 32 random bytes\n const privateKey = generatePrivateKey();\n\n // The fiber node expects different formats:\n // - fiber/sk: raw 32 bytes\n // - ckb/key: hex string (64 characters)\n let keyData: string | Uint8Array;\n if (type === 'fiber') {\n keyData = privateKey;\n } else {\n keyData = Buffer.from(privateKey).toString('hex');\n }\n\n // Write key file with restricted permissions\n writeFileSync(keyPath, keyData);\n chmodSync(keyPath, 0o600);\n\n return this.getKeyInfo(type);\n }\n\n /**\n * Get information about a key (without exposing the private key)\n */\n async getKeyInfo(type: 'fiber' | 'ckb'): Promise<KeyInfo> {\n const keyPath = type === 'fiber' ? this.fiberKeyPath : this.ckbKeyPath;\n\n if (!existsSync(keyPath)) {\n throw new Error(`Key not found: ${keyPath}`);\n }\n\n const keyData = readFileSync(keyPath);\n const encrypted = isEncryptedKey(keyData);\n\n // Get private key to derive public key\n const privateKey = await this.loadPrivateKey(type);\n const publicKey = await derivePublicKey(privateKey);\n\n return {\n publicKey,\n encrypted,\n path: keyPath,\n createdAt: Date.now(), // TODO: get actual file creation time\n };\n }\n\n /**\n * Load and decrypt a private key (for internal use only)\n * This should NEVER be exposed to the LLM context\n */\n private async loadPrivateKey(type: 'fiber' | 'ckb'): Promise<Uint8Array> {\n const keyPath = type === 'fiber' ? this.fiberKeyPath : this.ckbKeyPath;\n const keyData = readFileSync(keyPath);\n\n if (isEncryptedKey(keyData)) {\n if (!this.config.encryptionPassword) {\n throw new Error('Key is encrypted but no password provided');\n }\n return await decryptKey(keyData, this.config.encryptionPassword);\n }\n\n // The fiber node stores keys in different formats:\n // - fiber/sk: raw 32 bytes\n // - ckb/key: hex string (64 characters)\n if (type === 'fiber') {\n return new Uint8Array(keyData);\n } else {\n const hexString = keyData.toString('utf-8').trim();\n return new Uint8Array(Buffer.from(hexString, 'hex'));\n }\n }\n\n /**\n * Export keys for use with the Fiber node process\n * Returns the password to use for FIBER_SECRET_KEY_PASSWORD env var\n */\n getNodeKeyConfig(): { password?: string } {\n return {\n password: this.config.encryptionPassword,\n };\n }\n}\n\n/**\n * Create a key manager with environment-based configuration\n */\nexport function createKeyManager(baseDir: string, options?: Partial<KeyConfig>): KeyManager {\n const password = process.env.FIBER_KEY_PASSWORD || options?.encryptionPassword;\n\n return new KeyManager({\n baseDir,\n encryptionPassword: password,\n autoGenerate: options?.autoGenerate ?? true,\n });\n}\n"],"mappings":"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","names":["platform","existsSync","mkdirSync","join","promisify","existsSync","mkdirSync","dirname","join","join","existsSync","mkdirSync","dirname","chmodSync","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fiber-pay/node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Fiber Network node binary management and process lifecycle",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"node": ">=20"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@fiber-pay/sdk": "0.
|
|
33
|
+
"@fiber-pay/sdk": "0.2.0"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsup",
|