@btc-vision/cli 1.0.0 → 1.0.1
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/build/commands/AcceptCommand.js +2 -2
- package/build/commands/CompileCommand.js +3 -3
- package/build/commands/ConfigCommand.js +3 -7
- package/build/commands/DeprecateCommand.js +2 -2
- package/build/commands/InfoCommand.js +2 -2
- package/build/commands/InitCommand.d.ts +2 -0
- package/build/commands/InitCommand.js +113 -19
- package/build/commands/InstallCommand.js +1 -1
- package/build/commands/KeygenCommand.js +1 -1
- package/build/commands/ListCommand.js +6 -2
- package/build/commands/LoginCommand.js +22 -10
- package/build/commands/LogoutCommand.js +1 -1
- package/build/commands/PublishCommand.js +3 -3
- package/build/commands/SearchCommand.js +1 -1
- package/build/commands/SignCommand.js +6 -3
- package/build/commands/TransferCommand.js +3 -3
- package/build/commands/UndeprecateCommand.js +1 -1
- package/build/commands/VerifyCommand.js +5 -2
- package/build/commands/WhoamiCommand.js +1 -1
- package/build/lib/PackageRegistry.abi.js +1 -1
- package/build/lib/binary.js +8 -5
- package/build/lib/config.d.ts +1 -1
- package/build/lib/credentials.d.ts +1 -1
- package/build/lib/ipfs.js +3 -2
- package/build/lib/manifest.d.ts +1 -1
- package/build/lib/manifest.js +22 -11
- package/build/lib/provider.js +1 -1
- package/build/lib/registry.d.ts +1 -1
- package/build/lib/wallet.d.ts +5 -5
- package/build/lib/wallet.js +31 -31
- package/build/types/PackageRegistry.d.ts +1 -1
- package/build/types/index.js +1 -1
- package/package.json +3 -3
- package/src/commands/InitCommand.ts +86 -4
- package/src/lib/config.ts +3 -4
- package/src/lib/ipfs.ts +0 -1
- package/src/lib/manifest.ts +30 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { confirm } from '@inquirer/prompts';
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { getPendingScopeTransfer, getPendingTransfer } from '../lib/registry.js';
|
|
4
|
+
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
5
|
import { CLIWallet } from '../lib/wallet.js';
|
|
6
6
|
export class AcceptCommand extends BaseCommand {
|
|
7
7
|
constructor() {
|
|
@@ -3,10 +3,10 @@ import * as path from 'path';
|
|
|
3
3
|
import * as esbuild from 'esbuild';
|
|
4
4
|
import bytenode from 'bytenode';
|
|
5
5
|
import { BaseCommand } from './BaseCommand.js';
|
|
6
|
-
import {
|
|
7
|
-
import { buildOpnetBinary,
|
|
6
|
+
import { getManifestPath, loadManifest } from '../lib/manifest.js';
|
|
7
|
+
import { buildOpnetBinary, computeChecksum, formatFileSize } from '../lib/binary.js';
|
|
8
8
|
import { CLIWallet } from '../lib/wallet.js';
|
|
9
|
-
import {
|
|
9
|
+
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
10
10
|
export class CompileCommand extends BaseCommand {
|
|
11
11
|
constructor() {
|
|
12
12
|
super('compile', 'Compile plugin to .opnet binary format');
|
|
@@ -2,7 +2,7 @@ import { Command } from 'commander';
|
|
|
2
2
|
import * as os from 'os';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { BaseCommand } from './BaseCommand.js';
|
|
5
|
-
import {
|
|
5
|
+
import { displayConfig, getConfigValue, saveConfig, setConfigValue } from '../lib/config.js';
|
|
6
6
|
export class ConfigCommand extends BaseCommand {
|
|
7
7
|
constructor() {
|
|
8
8
|
super('config', 'Manage CLI configuration');
|
|
@@ -33,9 +33,7 @@ export class ConfigCommand extends BaseCommand {
|
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
createListCommand() {
|
|
36
|
-
return new Command('list')
|
|
37
|
-
.description('List all configuration values')
|
|
38
|
-
.action(() => {
|
|
36
|
+
return new Command('list').description('List all configuration values').action(() => {
|
|
39
37
|
this.handleList();
|
|
40
38
|
});
|
|
41
39
|
}
|
|
@@ -48,9 +46,7 @@ export class ConfigCommand extends BaseCommand {
|
|
|
48
46
|
});
|
|
49
47
|
}
|
|
50
48
|
createPathCommand() {
|
|
51
|
-
return new Command('path')
|
|
52
|
-
.description('Show configuration file path')
|
|
53
|
-
.action(() => {
|
|
49
|
+
return new Command('path').description('Show configuration file path').action(() => {
|
|
54
50
|
this.handlePath();
|
|
55
51
|
});
|
|
56
52
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { confirm, input } from '@inquirer/prompts';
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
3
|
import { getPackage, getVersion, isVersionImmutable } from '../lib/registry.js';
|
|
4
|
-
import {
|
|
4
|
+
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
5
|
import { CLIWallet } from '../lib/wallet.js';
|
|
6
6
|
export class DeprecateCommand extends BaseCommand {
|
|
7
7
|
constructor() {
|
|
@@ -2,8 +2,8 @@ import * as fs from 'fs';
|
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import * as crypto from 'crypto';
|
|
4
4
|
import { BaseCommand } from './BaseCommand.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { formatFileSize, getParsedMldsaLevel, parseOpnetBinary } from '../lib/binary.js';
|
|
6
|
+
import { getManifestPath, loadManifest } from '../lib/manifest.js';
|
|
7
7
|
export class InfoCommand extends BaseCommand {
|
|
8
8
|
constructor() {
|
|
9
9
|
super('info', 'Display information about a plugin or .opnet file');
|
|
@@ -11,6 +11,8 @@ export declare class InitCommand extends BaseCommand {
|
|
|
11
11
|
private createEntryPoint;
|
|
12
12
|
private createGitignore;
|
|
13
13
|
private createReadme;
|
|
14
|
+
private createEslintConfig;
|
|
15
|
+
private createPrettierConfig;
|
|
14
16
|
private toPascalCase;
|
|
15
17
|
}
|
|
16
18
|
export declare const initCommand: import("commander").Command;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import { input, select
|
|
3
|
+
import { confirm, input, select } from '@inquirer/prompts';
|
|
4
4
|
import { BaseCommand } from './BaseCommand.js';
|
|
5
5
|
import { validatePluginName } from '../lib/manifest.js';
|
|
6
6
|
export class InitCommand extends BaseCommand {
|
|
@@ -45,21 +45,29 @@ export class InitCommand extends BaseCommand {
|
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
this.logger.info('\nOPNet Plugin Initialization\n');
|
|
48
|
-
const pluginName = name ||
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
const pluginName = name ||
|
|
49
|
+
(await input({
|
|
50
|
+
message: 'Plugin name:',
|
|
51
|
+
default: path.basename(process.cwd()),
|
|
52
|
+
validate: (value) => {
|
|
53
|
+
const errors = validatePluginName(value);
|
|
54
|
+
return errors.length > 0 ? errors[0] : true;
|
|
55
|
+
},
|
|
56
|
+
}));
|
|
57
|
+
const description = (await input({ message: 'Description:', default: '' })) || undefined;
|
|
58
|
+
const authorName = await input({
|
|
59
|
+
message: 'Author name:',
|
|
60
|
+
default: process.env.USER || 'Author',
|
|
55
61
|
});
|
|
56
|
-
const
|
|
57
|
-
const authorName = await input({ message: 'Author name:', default: process.env.USER || 'Author' });
|
|
58
|
-
const authorEmail = await input({ message: 'Author email (optional):', default: '' }) || undefined;
|
|
62
|
+
const authorEmail = (await input({ message: 'Author email (optional):', default: '' })) || undefined;
|
|
59
63
|
const pluginType = await select({
|
|
60
64
|
message: 'Plugin type:',
|
|
61
65
|
choices: [
|
|
62
|
-
{
|
|
66
|
+
{
|
|
67
|
+
name: 'Standalone',
|
|
68
|
+
value: 'standalone',
|
|
69
|
+
description: 'Independent plugin',
|
|
70
|
+
},
|
|
63
71
|
{ name: 'Library', value: 'library', description: 'Shared library' },
|
|
64
72
|
],
|
|
65
73
|
default: options?.template || 'standalone',
|
|
@@ -74,7 +82,10 @@ export class InitCommand extends BaseCommand {
|
|
|
74
82
|
const projectDir = process.cwd();
|
|
75
83
|
const pluginJsonPath = path.join(projectDir, 'plugin.json');
|
|
76
84
|
if (fs.existsSync(pluginJsonPath) && !force) {
|
|
77
|
-
const overwrite = await confirm({
|
|
85
|
+
const overwrite = await confirm({
|
|
86
|
+
message: 'plugin.json exists. Overwrite?',
|
|
87
|
+
default: false,
|
|
88
|
+
});
|
|
78
89
|
if (!overwrite) {
|
|
79
90
|
this.logger.warn('Initialization cancelled.');
|
|
80
91
|
return;
|
|
@@ -94,6 +105,8 @@ export class InitCommand extends BaseCommand {
|
|
|
94
105
|
this.createEntryPoint(projectDir, config, force);
|
|
95
106
|
this.createGitignore(projectDir, force);
|
|
96
107
|
this.createReadme(projectDir, config, force);
|
|
108
|
+
this.createEslintConfig(projectDir, force);
|
|
109
|
+
this.createPrettierConfig(projectDir, force);
|
|
97
110
|
}
|
|
98
111
|
createPluginJson(projectDir, config) {
|
|
99
112
|
const manifest = {
|
|
@@ -103,7 +116,6 @@ export class InitCommand extends BaseCommand {
|
|
|
103
116
|
main: 'dist/index.jsc',
|
|
104
117
|
target: 'bytenode',
|
|
105
118
|
type: 'plugin',
|
|
106
|
-
checksum: '',
|
|
107
119
|
author: config.authorEmail
|
|
108
120
|
? { name: config.authorName, email: config.authorEmail }
|
|
109
121
|
: { name: config.authorName },
|
|
@@ -185,14 +197,25 @@ export class InitCommand extends BaseCommand {
|
|
|
185
197
|
main: 'dist/index.js',
|
|
186
198
|
scripts: {
|
|
187
199
|
build: 'tsc',
|
|
188
|
-
compile: 'opnet compile',
|
|
189
|
-
verify: 'opnet verify',
|
|
200
|
+
compile: 'npx opnet compile',
|
|
201
|
+
verify: 'npx opnet verify',
|
|
190
202
|
lint: 'eslint src/',
|
|
203
|
+
format: 'prettier --write src/',
|
|
191
204
|
},
|
|
192
|
-
author: config.authorEmail
|
|
205
|
+
author: config.authorEmail
|
|
206
|
+
? `${config.authorName} <${config.authorEmail}>`
|
|
207
|
+
: config.authorName,
|
|
193
208
|
license: 'Apache-2.0',
|
|
194
209
|
dependencies: { '@btc-vision/plugin-sdk': '^1.0.0' },
|
|
195
|
-
devDependencies: {
|
|
210
|
+
devDependencies: {
|
|
211
|
+
'@eslint/js': '^9.39.0',
|
|
212
|
+
'@types/node': '^25.0.0',
|
|
213
|
+
eslint: '^9.39.0',
|
|
214
|
+
prettier: '^3.6.0',
|
|
215
|
+
typescript: '^5.8.0',
|
|
216
|
+
'typescript-eslint': '^8.39.0',
|
|
217
|
+
'@btc-vision/cli': '^1.0.0',
|
|
218
|
+
},
|
|
196
219
|
};
|
|
197
220
|
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4));
|
|
198
221
|
this.logger.success(' Created package.json');
|
|
@@ -329,8 +352,79 @@ Apache-2.0
|
|
|
329
352
|
`);
|
|
330
353
|
this.logger.success(' Created README.md');
|
|
331
354
|
}
|
|
355
|
+
createEslintConfig(projectDir, force) {
|
|
356
|
+
const eslintPath = path.join(projectDir, 'eslint.config.js');
|
|
357
|
+
if (fs.existsSync(eslintPath) && !force)
|
|
358
|
+
return;
|
|
359
|
+
const content = `// @ts-check
|
|
360
|
+
|
|
361
|
+
import eslint from '@eslint/js';
|
|
362
|
+
import tseslint from 'typescript-eslint';
|
|
363
|
+
|
|
364
|
+
export default tseslint.config(
|
|
365
|
+
eslint.configs.recommended,
|
|
366
|
+
...tseslint.configs.strictTypeChecked,
|
|
367
|
+
{
|
|
368
|
+
languageOptions: {
|
|
369
|
+
parserOptions: {
|
|
370
|
+
projectService: true,
|
|
371
|
+
tsconfigDirName: import.meta.dirname,
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
rules: {
|
|
375
|
+
'no-undef': 'off',
|
|
376
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
377
|
+
'no-empty': 'off',
|
|
378
|
+
'@typescript-eslint/restrict-template-expressions': 'off',
|
|
379
|
+
'@typescript-eslint/only-throw-error': 'off',
|
|
380
|
+
'@typescript-eslint/no-unnecessary-condition': 'off',
|
|
381
|
+
'@typescript-eslint/unbound-method': 'warn',
|
|
382
|
+
'@typescript-eslint/no-confusing-void-expression': 'off',
|
|
383
|
+
'@typescript-eslint/no-extraneous-class': 'off',
|
|
384
|
+
'no-async-promise-executor': 'off',
|
|
385
|
+
'@typescript-eslint/no-misused-promises': 'off',
|
|
386
|
+
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
|
|
387
|
+
'@typescript-eslint/no-duplicate-enum-values': 'off',
|
|
388
|
+
'prefer-spread': 'off',
|
|
389
|
+
'@typescript-eslint/no-empty-object-type': 'off',
|
|
390
|
+
'@typescript-eslint/no-base-to-string': 'off',
|
|
391
|
+
'@typescript-eslint/no-dynamic-delete': 'off',
|
|
392
|
+
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
files: ['**/*.js'],
|
|
397
|
+
...tseslint.configs.disableTypeChecked,
|
|
398
|
+
},
|
|
399
|
+
);
|
|
400
|
+
`;
|
|
401
|
+
fs.writeFileSync(eslintPath, content);
|
|
402
|
+
this.logger.success(' Created eslint.config.js');
|
|
403
|
+
}
|
|
404
|
+
createPrettierConfig(projectDir, force) {
|
|
405
|
+
const prettierPath = path.join(projectDir, '.prettierrc.json');
|
|
406
|
+
if (fs.existsSync(prettierPath) && !force)
|
|
407
|
+
return;
|
|
408
|
+
const config = {
|
|
409
|
+
printWidth: 100,
|
|
410
|
+
trailingComma: 'all',
|
|
411
|
+
tabWidth: 4,
|
|
412
|
+
semi: true,
|
|
413
|
+
singleQuote: true,
|
|
414
|
+
quoteProps: 'as-needed',
|
|
415
|
+
bracketSpacing: true,
|
|
416
|
+
bracketSameLine: true,
|
|
417
|
+
arrowParens: 'always',
|
|
418
|
+
singleAttributePerLine: true,
|
|
419
|
+
};
|
|
420
|
+
fs.writeFileSync(prettierPath, JSON.stringify(config, null, 4));
|
|
421
|
+
this.logger.success(' Created .prettierrc.json');
|
|
422
|
+
}
|
|
332
423
|
toPascalCase(str) {
|
|
333
|
-
return str
|
|
424
|
+
return str
|
|
425
|
+
.split(/[-_]/)
|
|
426
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
|
|
427
|
+
.join('');
|
|
334
428
|
}
|
|
335
429
|
}
|
|
336
430
|
export const initCommand = new InitCommand().getCommand();
|
|
@@ -3,7 +3,7 @@ import * as path from 'path';
|
|
|
3
3
|
import { BaseCommand } from './BaseCommand.js';
|
|
4
4
|
import { getPackage, getVersion, registryToMldsaLevel } from '../lib/registry.js';
|
|
5
5
|
import { fetchFromIPFS, isValidCid } from '../lib/ipfs.js';
|
|
6
|
-
import { parseOpnetBinary, verifyChecksum
|
|
6
|
+
import { formatFileSize, parseOpnetBinary, verifyChecksum } from '../lib/binary.js';
|
|
7
7
|
import { CLIWallet } from '../lib/wallet.js';
|
|
8
8
|
export class InstallCommand extends BaseCommand {
|
|
9
9
|
constructor() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import { BaseCommand } from './BaseCommand.js';
|
|
4
|
-
import { generateMLDSAKeypair, generateMnemonic
|
|
4
|
+
import { computePublicKeyHash, generateMLDSAKeypair, generateMnemonic } from '../lib/wallet.js';
|
|
5
5
|
import { isValidMldsaLevel } from '../lib/credentials.js';
|
|
6
6
|
export class KeygenCommand extends BaseCommand {
|
|
7
7
|
constructor() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { BaseCommand } from './BaseCommand.js';
|
|
4
|
-
import {
|
|
4
|
+
import { formatFileSize, parseOpnetBinary } from '../lib/binary.js';
|
|
5
5
|
export class ListCommand extends BaseCommand {
|
|
6
6
|
constructor() {
|
|
7
7
|
super('list', 'List installed plugins');
|
|
@@ -98,7 +98,11 @@ export class ListCommand extends BaseCommand {
|
|
|
98
98
|
const versionWidth = 12;
|
|
99
99
|
const typeWidth = 12;
|
|
100
100
|
const sizeWidth = 10;
|
|
101
|
-
this.logger.info('Name'.padEnd(nameWidth) +
|
|
101
|
+
this.logger.info('Name'.padEnd(nameWidth) +
|
|
102
|
+
'Version'.padEnd(versionWidth) +
|
|
103
|
+
'Type'.padEnd(typeWidth) +
|
|
104
|
+
'Size'.padEnd(sizeWidth) +
|
|
105
|
+
'Signed');
|
|
102
106
|
this.logger.info('─'.repeat(nameWidth + versionWidth + typeWidth + sizeWidth + 8));
|
|
103
107
|
for (const plugin of plugins) {
|
|
104
108
|
const signedText = plugin.signed ? 'Yes' : 'No';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { confirm, password, select } from '@inquirer/prompts';
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { isValidMldsaLevel, isValidNetwork, saveCredentials } from '../lib/credentials.js';
|
|
4
|
+
import { CLIWallet, validateMnemonic } from '../lib/wallet.js';
|
|
5
5
|
export class LoginCommand extends BaseCommand {
|
|
6
6
|
constructor() {
|
|
7
7
|
super('login', 'Configure wallet credentials for signing and publishing');
|
|
@@ -95,7 +95,7 @@ export class LoginCommand extends BaseCommand {
|
|
|
95
95
|
},
|
|
96
96
|
],
|
|
97
97
|
});
|
|
98
|
-
const selectedNetwork = await select({
|
|
98
|
+
const selectedNetwork = (await select({
|
|
99
99
|
message: 'Select network:',
|
|
100
100
|
choices: [
|
|
101
101
|
{ name: 'Mainnet', value: 'mainnet' },
|
|
@@ -103,16 +103,28 @@ export class LoginCommand extends BaseCommand {
|
|
|
103
103
|
{ name: 'Regtest', value: 'regtest' },
|
|
104
104
|
],
|
|
105
105
|
default: defaultNetwork,
|
|
106
|
-
});
|
|
107
|
-
const selectedLevel = await select({
|
|
106
|
+
}));
|
|
107
|
+
const selectedLevel = (await select({
|
|
108
108
|
message: 'Select MLDSA security level:',
|
|
109
109
|
choices: [
|
|
110
|
-
{
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
{
|
|
111
|
+
name: 'MLDSA-44 (Level 2, fastest)',
|
|
112
|
+
value: 44,
|
|
113
|
+
description: '1312 byte public key',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'MLDSA-65 (Level 3, balanced)',
|
|
117
|
+
value: 65,
|
|
118
|
+
description: '1952 byte public key',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'MLDSA-87 (Level 5, most secure)',
|
|
122
|
+
value: 87,
|
|
123
|
+
description: '2592 byte public key',
|
|
124
|
+
},
|
|
113
125
|
],
|
|
114
126
|
default: defaultLevel,
|
|
115
|
-
});
|
|
127
|
+
}));
|
|
116
128
|
if (loginMethod === 'mnemonic') {
|
|
117
129
|
const mnemonic = await password({
|
|
118
130
|
message: 'Enter your mnemonic phrase (12 or 24 words):',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { confirm } from '@inquirer/prompts';
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
-
import { deleteCredentials,
|
|
3
|
+
import { deleteCredentials, getCredentialSource, hasCredentials } from '../lib/credentials.js';
|
|
4
4
|
export class LogoutCommand extends BaseCommand {
|
|
5
5
|
constructor() {
|
|
6
6
|
super('logout', 'Remove stored wallet credentials');
|
|
@@ -3,11 +3,11 @@ import * as path from 'path';
|
|
|
3
3
|
import * as crypto from 'crypto';
|
|
4
4
|
import { confirm } from '@inquirer/prompts';
|
|
5
5
|
import { BaseCommand } from './BaseCommand.js';
|
|
6
|
-
import {
|
|
6
|
+
import { formatFileSize, parseOpnetBinary, verifyChecksum } from '../lib/binary.js';
|
|
7
7
|
import { CLIWallet } from '../lib/wallet.js';
|
|
8
|
-
import {
|
|
8
|
+
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
9
9
|
import { uploadPlugin } from '../lib/ipfs.js';
|
|
10
|
-
import {
|
|
10
|
+
import { computePermissionsHash, encodeDependencies, getPackage, getScope, mldsaLevelToRegistry, parsePackageName, pluginTypeToRegistry, } from '../lib/registry.js';
|
|
11
11
|
export class PublishCommand extends BaseCommand {
|
|
12
12
|
constructor() {
|
|
13
13
|
super('publish', 'Publish a plugin to the OPNet registry');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseCommand } from './BaseCommand.js';
|
|
2
|
-
import { getPackage, getVersion, registryToMldsaLevel, registryToPluginType } from '../lib/registry.js';
|
|
2
|
+
import { getPackage, getVersion, registryToMldsaLevel, registryToPluginType, } from '../lib/registry.js';
|
|
3
3
|
export class SearchCommand extends BaseCommand {
|
|
4
4
|
constructor() {
|
|
5
5
|
super('search', 'Search for plugins in the registry');
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as crypto from 'crypto';
|
|
3
3
|
import { BaseCommand } from './BaseCommand.js';
|
|
4
|
-
import {
|
|
4
|
+
import { buildOpnetBinary, computeChecksum, formatFileSize, parseOpnetBinary, } from '../lib/binary.js';
|
|
5
5
|
import { CLIWallet } from '../lib/wallet.js';
|
|
6
|
-
import {
|
|
6
|
+
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
7
7
|
export class SignCommand extends BaseCommand {
|
|
8
8
|
constructor() {
|
|
9
9
|
super('sign', 'Sign or re-sign a .opnet binary with your MLDSA key');
|
|
@@ -34,7 +34,10 @@ export class SignCommand extends BaseCommand {
|
|
|
34
34
|
const parsed = parseOpnetBinary(data);
|
|
35
35
|
this.logger.success(`Parsed: ${parsed.metadata.name}@${parsed.metadata.version}`);
|
|
36
36
|
const isUnsigned = parsed.publicKey.every((b) => b === 0);
|
|
37
|
-
const currentPkHash = crypto
|
|
37
|
+
const currentPkHash = crypto
|
|
38
|
+
.createHash('sha256')
|
|
39
|
+
.update(parsed.publicKey)
|
|
40
|
+
.digest('hex');
|
|
38
41
|
const newPkHash = wallet.mldsaPublicKeyHash;
|
|
39
42
|
if (!isUnsigned && currentPkHash !== newPkHash && !options.force) {
|
|
40
43
|
this.logger.log('');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { confirm, input } from '@inquirer/prompts';
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
-
import { getPackage,
|
|
4
|
-
import {
|
|
3
|
+
import { getPackage, getPendingScopeTransfer, getPendingTransfer, getScope, } from '../lib/registry.js';
|
|
4
|
+
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
5
|
import { CLIWallet } from '../lib/wallet.js';
|
|
6
6
|
export class TransferCommand extends BaseCommand {
|
|
7
7
|
constructor() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { confirm } from '@inquirer/prompts';
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
3
|
import { getPackage, getVersion, isVersionImmutable } from '../lib/registry.js';
|
|
4
|
-
import {
|
|
4
|
+
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
5
|
import { CLIWallet } from '../lib/wallet.js';
|
|
6
6
|
export class UndeprecateCommand extends BaseCommand {
|
|
7
7
|
constructor() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as crypto from 'crypto';
|
|
3
3
|
import { BaseCommand } from './BaseCommand.js';
|
|
4
|
-
import { parseOpnetBinary, verifyChecksum
|
|
4
|
+
import { formatFileSize, parseOpnetBinary, verifyChecksum } from '../lib/binary.js';
|
|
5
5
|
import { CLIWallet } from '../lib/wallet.js';
|
|
6
6
|
export class VerifyCommand extends BaseCommand {
|
|
7
7
|
constructor() {
|
|
@@ -68,7 +68,10 @@ export class VerifyCommand extends BaseCommand {
|
|
|
68
68
|
signatureError,
|
|
69
69
|
isUnsigned,
|
|
70
70
|
metadata: parsed.metadata,
|
|
71
|
-
publicKeyHash: crypto
|
|
71
|
+
publicKeyHash: crypto
|
|
72
|
+
.createHash('sha256')
|
|
73
|
+
.update(parsed.publicKey)
|
|
74
|
+
.digest('hex'),
|
|
72
75
|
bytecodeSize: parsed.bytecode.length,
|
|
73
76
|
protoSize: parsed.proto?.length ?? 0,
|
|
74
77
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseCommand } from './BaseCommand.js';
|
|
2
|
-
import {
|
|
2
|
+
import { getCredentialSource, hasCredentials, loadCredentials, maskSensitive, } from '../lib/credentials.js';
|
|
3
3
|
import { CLIWallet } from '../lib/wallet.js';
|
|
4
4
|
export class WhoamiCommand extends BaseCommand {
|
|
5
5
|
constructor() {
|
package/build/lib/binary.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as crypto from 'crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { MLDSA_PUBLIC_KEY_SIZES, MLDSA_SIGNATURE_SIZES, PLUGIN_FORMAT_VERSION, PLUGIN_MAGIC_BYTES, } from '@btc-vision/plugin-sdk';
|
|
3
3
|
import { cliLevelToMLDSALevel, mldsaLevelToCLI } from '../types/index.js';
|
|
4
4
|
export function parseOpnetBinary(data) {
|
|
5
5
|
let offset = 0;
|
|
@@ -91,7 +91,7 @@ export function verifyChecksum(parsed) {
|
|
|
91
91
|
return computed.equals(parsed.checksum);
|
|
92
92
|
}
|
|
93
93
|
export function buildOpnetBinary(options) {
|
|
94
|
-
const { mldsaLevel, publicKey, signature, metadata, bytecode, proto = Buffer.alloc(0) } = options;
|
|
94
|
+
const { mldsaLevel, publicKey, signature, metadata, bytecode, proto = Buffer.alloc(0), } = options;
|
|
95
95
|
const sdkLevel = cliLevelToMLDSALevel(mldsaLevel);
|
|
96
96
|
const expectedPkSize = MLDSA_PUBLIC_KEY_SIZES[sdkLevel];
|
|
97
97
|
const expectedSigSize = MLDSA_SIGNATURE_SIZES[sdkLevel];
|
|
@@ -109,9 +109,12 @@ export function buildOpnetBinary(options) {
|
|
|
109
109
|
1 +
|
|
110
110
|
publicKey.length +
|
|
111
111
|
signature.length +
|
|
112
|
-
4 +
|
|
113
|
-
|
|
114
|
-
4 +
|
|
112
|
+
4 +
|
|
113
|
+
metadataBytes.length +
|
|
114
|
+
4 +
|
|
115
|
+
bytecode.length +
|
|
116
|
+
4 +
|
|
117
|
+
proto.length +
|
|
115
118
|
32;
|
|
116
119
|
const buffer = Buffer.alloc(totalSize);
|
|
117
120
|
let offset = 0;
|
package/build/lib/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CLIConfig,
|
|
1
|
+
import { CLIConfig, CLIMldsaLevel, NetworkName } from '../types/index.js';
|
|
2
2
|
export declare function ensureConfigDir(): void;
|
|
3
3
|
export declare function loadConfig(): CLIConfig;
|
|
4
4
|
export declare function saveConfig(config: CLIConfig): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CLICredentials,
|
|
1
|
+
import { CLICredentials, CLIMldsaLevel, NetworkName } from '../types/index.js';
|
|
2
2
|
export declare function loadCredentials(): CLICredentials | null;
|
|
3
3
|
export declare function saveCredentials(credentials: CLICredentials): void;
|
|
4
4
|
export declare function deleteCredentials(): boolean;
|
package/build/lib/ipfs.js
CHANGED
|
@@ -62,7 +62,9 @@ export async function pinToIPFS(data, name) {
|
|
|
62
62
|
'Content-Length': body.length.toString(),
|
|
63
63
|
};
|
|
64
64
|
if (config.ipfsPinningAuthHeader) {
|
|
65
|
-
const [headerName, headerValue] = config.ipfsPinningAuthHeader
|
|
65
|
+
const [headerName, headerValue] = config.ipfsPinningAuthHeader
|
|
66
|
+
.split(':')
|
|
67
|
+
.map((s) => s.trim());
|
|
66
68
|
if (headerName && headerValue) {
|
|
67
69
|
headers[headerName] = headerValue;
|
|
68
70
|
}
|
|
@@ -139,7 +141,6 @@ export async function fetchFromIPFS(cid) {
|
|
|
139
141
|
}
|
|
140
142
|
catch (error) {
|
|
141
143
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
142
|
-
continue;
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
146
|
throw new Error(`Failed to fetch from all gateways: ${lastError?.message}`);
|
package/build/lib/manifest.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ export declare function createManifest(options: {
|
|
|
10
10
|
email?: string;
|
|
11
11
|
description?: string;
|
|
12
12
|
pluginType: 'standalone' | 'library';
|
|
13
|
-
}): IPluginMetadata
|
|
13
|
+
}): Omit<IPluginMetadata, 'checksum'>;
|
|
14
14
|
export declare function getManifestPath(dir?: string): string;
|
package/build/lib/manifest.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import { DEFAULT_LIFECYCLE, DEFAULT_PERMISSIONS, DEFAULT_RESOURCES, PLUGIN_MANIFEST_FILENAME, PLUGIN_NAME_REGEX, validateManifest as sdkValidateManifest, } from '@btc-vision/plugin-sdk';
|
|
4
4
|
const SCOPED_NAME_PATTERN = /^@[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/;
|
|
5
5
|
export function validatePluginName(name) {
|
|
6
6
|
const errors = [];
|
|
@@ -29,8 +29,7 @@ export function validateManifest(manifest) {
|
|
|
29
29
|
export function validatePermissions(permissions) {
|
|
30
30
|
const errors = [];
|
|
31
31
|
if (permissions.database?.enabled) {
|
|
32
|
-
if (!permissions.database.collections ||
|
|
33
|
-
!Array.isArray(permissions.database.collections)) {
|
|
32
|
+
if (!permissions.database.collections || !Array.isArray(permissions.database.collections)) {
|
|
34
33
|
errors.push('database.collections must be an array when database is enabled');
|
|
35
34
|
}
|
|
36
35
|
}
|
|
@@ -49,14 +48,27 @@ export function loadManifest(manifestPath) {
|
|
|
49
48
|
catch (e) {
|
|
50
49
|
throw new Error(`Failed to parse manifest: ${e instanceof Error ? e.message : String(e)}`);
|
|
51
50
|
}
|
|
52
|
-
const
|
|
53
|
-
if (!
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
const errors = [];
|
|
52
|
+
if (!manifest.name || typeof manifest.name !== 'string') {
|
|
53
|
+
errors.push('name is required');
|
|
54
|
+
}
|
|
55
|
+
if (!manifest.version || typeof manifest.version !== 'string') {
|
|
56
|
+
errors.push('version is required');
|
|
57
|
+
}
|
|
58
|
+
if (!manifest.author || typeof manifest.author !== 'object') {
|
|
59
|
+
errors.push('author is required');
|
|
60
|
+
}
|
|
61
|
+
if (!manifest.pluginType || !['standalone', 'library'].includes(manifest.pluginType)) {
|
|
62
|
+
errors.push('pluginType must be "standalone" or "library"');
|
|
63
|
+
}
|
|
64
|
+
if (errors.length > 0) {
|
|
65
|
+
throw new Error(`Invalid manifest:\n${errors.map((e) => ` - ${e}`).join('\n')}`);
|
|
66
|
+
}
|
|
67
|
+
const result = manifest;
|
|
68
|
+
if (!result.checksum) {
|
|
69
|
+
result.checksum = '';
|
|
58
70
|
}
|
|
59
|
-
return
|
|
71
|
+
return result;
|
|
60
72
|
}
|
|
61
73
|
export function saveManifest(manifestPath, manifest) {
|
|
62
74
|
const content = JSON.stringify(manifest, null, 4);
|
|
@@ -70,7 +82,6 @@ export function createManifest(options) {
|
|
|
70
82
|
main: 'dist/index.jsc',
|
|
71
83
|
target: 'bytenode',
|
|
72
84
|
type: 'plugin',
|
|
73
|
-
checksum: '',
|
|
74
85
|
author: {
|
|
75
86
|
name: options.author,
|
|
76
87
|
email: options.email,
|
package/build/lib/provider.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JSONRpcProvider } from 'opnet';
|
|
2
|
-
import {
|
|
2
|
+
import { getRegistryAddress, getRpcUrl, loadConfig } from './config.js';
|
|
3
3
|
import { getNetwork } from './wallet.js';
|
|
4
4
|
const DEFAULT_TIMEOUT = 30000;
|
|
5
5
|
const providerCache = new Map();
|
package/build/lib/registry.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Address } from '@btc-vision/transaction';
|
|
2
|
-
import {
|
|
2
|
+
import { CLIMldsaLevel, NetworkName, RegistryPluginType } from '../types/index.js';
|
|
3
3
|
import { IPluginPermissions } from '@btc-vision/plugin-sdk';
|
|
4
4
|
import { IPackageRegistry } from '../types/PackageRegistry.js';
|
|
5
5
|
export interface ScopeInfo {
|
package/build/lib/wallet.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Network } from '@btc-vision/bitcoin';
|
|
2
2
|
import { MLDSASecurityLevel } from '@btc-vision/bip32';
|
|
3
|
-
import {
|
|
4
|
-
import { CLICredentials,
|
|
3
|
+
import { EcKeyPair, Wallet } from '@btc-vision/transaction';
|
|
4
|
+
import { CLICredentials, CLIMldsaLevel, NetworkName } from '../types/index.js';
|
|
5
5
|
export declare function getNetwork(networkName: NetworkName): Network;
|
|
6
6
|
export declare function getMLDSASecurityLevel(level: CLIMldsaLevel): MLDSASecurityLevel;
|
|
7
7
|
export declare class CLIWallet {
|
|
@@ -9,8 +9,6 @@ export declare class CLIWallet {
|
|
|
9
9
|
private readonly network;
|
|
10
10
|
private readonly mldsaLevel;
|
|
11
11
|
private constructor();
|
|
12
|
-
static fromCredentials(credentials: CLICredentials): CLIWallet;
|
|
13
|
-
static load(): CLIWallet;
|
|
14
12
|
get p2trAddress(): string;
|
|
15
13
|
get underlyingWallet(): Wallet;
|
|
16
14
|
get keypair(): EcKeyPair;
|
|
@@ -19,9 +17,11 @@ export declare class CLIWallet {
|
|
|
19
17
|
get mldsaPublicKeyHash(): string;
|
|
20
18
|
get securityLevel(): CLIMldsaLevel;
|
|
21
19
|
get walletNetwork(): Network;
|
|
20
|
+
static fromCredentials(credentials: CLICredentials): CLIWallet;
|
|
21
|
+
static load(): CLIWallet;
|
|
22
|
+
static verifyMLDSA(data: Buffer, signature: Buffer, publicKey: Buffer, level: CLIMldsaLevel): boolean;
|
|
22
23
|
signMLDSA(data: Buffer): Buffer;
|
|
23
24
|
verifyMLDSA(data: Buffer, signature: Buffer): boolean;
|
|
24
|
-
static verifyMLDSA(data: Buffer, signature: Buffer, publicKey: Buffer, level: CLIMldsaLevel): boolean;
|
|
25
25
|
}
|
|
26
26
|
export declare function generateMLDSAKeypair(level: CLIMldsaLevel): {
|
|
27
27
|
privateKey: Buffer;
|
package/build/lib/wallet.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { networks } from '@btc-vision/bitcoin';
|
|
2
2
|
import { MLDSASecurityLevel, QuantumBIP32Factory } from '@btc-vision/bip32';
|
|
3
|
-
import {
|
|
3
|
+
import { EcKeyPair, MessageSigner, Mnemonic, Wallet } from '@btc-vision/transaction';
|
|
4
4
|
import * as crypto from 'crypto';
|
|
5
|
-
import {
|
|
5
|
+
import { canSign, loadCredentials } from './credentials.js';
|
|
6
6
|
export function getNetwork(networkName) {
|
|
7
7
|
switch (networkName) {
|
|
8
8
|
case 'mainnet':
|
|
@@ -32,30 +32,6 @@ export class CLIWallet {
|
|
|
32
32
|
this.network = network;
|
|
33
33
|
this.mldsaLevel = mldsaLevel;
|
|
34
34
|
}
|
|
35
|
-
static fromCredentials(credentials) {
|
|
36
|
-
const network = getNetwork(credentials.network);
|
|
37
|
-
const securityLevel = getMLDSASecurityLevel(credentials.mldsaLevel);
|
|
38
|
-
if (credentials.mnemonic) {
|
|
39
|
-
const mnemonic = new Mnemonic(credentials.mnemonic, '', network, securityLevel);
|
|
40
|
-
const wallet = mnemonic.deriveUnisat();
|
|
41
|
-
return new CLIWallet(wallet, network, credentials.mldsaLevel);
|
|
42
|
-
}
|
|
43
|
-
if (credentials.wif && credentials.mldsaPrivateKey) {
|
|
44
|
-
const wallet = Wallet.fromWif(credentials.wif, credentials.mldsaPrivateKey, network, securityLevel);
|
|
45
|
-
return new CLIWallet(wallet, network, credentials.mldsaLevel);
|
|
46
|
-
}
|
|
47
|
-
throw new Error('Invalid credentials: requires either mnemonic or both WIF and MLDSA key');
|
|
48
|
-
}
|
|
49
|
-
static load() {
|
|
50
|
-
const credentials = loadCredentials();
|
|
51
|
-
if (!credentials) {
|
|
52
|
-
throw new Error('No credentials found. Run `opnet login` to configure your wallet.');
|
|
53
|
-
}
|
|
54
|
-
if (!canSign(credentials)) {
|
|
55
|
-
throw new Error('Credentials incomplete for signing. Run `opnet login` to reconfigure.');
|
|
56
|
-
}
|
|
57
|
-
return CLIWallet.fromCredentials(credentials);
|
|
58
|
-
}
|
|
59
35
|
get p2trAddress() {
|
|
60
36
|
return this.wallet.p2tr;
|
|
61
37
|
}
|
|
@@ -81,12 +57,29 @@ export class CLIWallet {
|
|
|
81
57
|
get walletNetwork() {
|
|
82
58
|
return this.network;
|
|
83
59
|
}
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
60
|
+
static fromCredentials(credentials) {
|
|
61
|
+
const network = getNetwork(credentials.network);
|
|
62
|
+
const securityLevel = getMLDSASecurityLevel(credentials.mldsaLevel);
|
|
63
|
+
if (credentials.mnemonic) {
|
|
64
|
+
const mnemonic = new Mnemonic(credentials.mnemonic, '', network, securityLevel);
|
|
65
|
+
const wallet = mnemonic.deriveUnisat();
|
|
66
|
+
return new CLIWallet(wallet, network, credentials.mldsaLevel);
|
|
67
|
+
}
|
|
68
|
+
if (credentials.wif && credentials.mldsaPrivateKey) {
|
|
69
|
+
const wallet = Wallet.fromWif(credentials.wif, credentials.mldsaPrivateKey, network, securityLevel);
|
|
70
|
+
return new CLIWallet(wallet, network, credentials.mldsaLevel);
|
|
71
|
+
}
|
|
72
|
+
throw new Error('Invalid credentials: requires either mnemonic or both WIF and MLDSA key');
|
|
87
73
|
}
|
|
88
|
-
|
|
89
|
-
|
|
74
|
+
static load() {
|
|
75
|
+
const credentials = loadCredentials();
|
|
76
|
+
if (!credentials) {
|
|
77
|
+
throw new Error('No credentials found. Run `opnet login` to configure your wallet.');
|
|
78
|
+
}
|
|
79
|
+
if (!canSign(credentials)) {
|
|
80
|
+
throw new Error('Credentials incomplete for signing. Run `opnet login` to reconfigure.');
|
|
81
|
+
}
|
|
82
|
+
return CLIWallet.fromCredentials(credentials);
|
|
90
83
|
}
|
|
91
84
|
static verifyMLDSA(data, signature, publicKey, level) {
|
|
92
85
|
const securityLevel = getMLDSASecurityLevel(level);
|
|
@@ -94,6 +87,13 @@ export class CLIWallet {
|
|
|
94
87
|
const keypair = QuantumBIP32Factory.fromPublicKey(publicKey, dummyChainCode, networks.bitcoin, securityLevel);
|
|
95
88
|
return keypair.verify(data, signature);
|
|
96
89
|
}
|
|
90
|
+
signMLDSA(data) {
|
|
91
|
+
const result = MessageSigner.signMLDSAMessage(this.wallet.mldsaKeypair, data);
|
|
92
|
+
return Buffer.from(result.signature);
|
|
93
|
+
}
|
|
94
|
+
verifyMLDSA(data, signature) {
|
|
95
|
+
return MessageSigner.verifyMLDSASignature(this.wallet.mldsaKeypair, data, signature);
|
|
96
|
+
}
|
|
97
97
|
}
|
|
98
98
|
export function generateMLDSAKeypair(level) {
|
|
99
99
|
const securityLevel = getMLDSASecurityLevel(level);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Address } from '@btc-vision/transaction';
|
|
2
|
-
import { CallResult,
|
|
2
|
+
import { CallResult, IOP_NETContract, OPNetEvent } from 'opnet';
|
|
3
3
|
export type TreasuryAddressChangedEvent = {
|
|
4
4
|
readonly previousAddressHash: bigint;
|
|
5
5
|
readonly newAddressHash: bigint;
|
package/build/types/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MLDSA_PUBLIC_KEY_SIZES, MLDSA_SIGNATURE_SIZES, MLDSALevel } from '@btc-vision/plugin-sdk';
|
|
2
2
|
export function cliLevelToMLDSALevel(level) {
|
|
3
3
|
switch (level) {
|
|
4
4
|
case 44:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for the OPNet plugin ecosystem - scaffolding, compilation, signing, and registry interaction",
|
|
6
6
|
"author": "OP_NET",
|
|
@@ -53,12 +53,12 @@
|
|
|
53
53
|
"bytenode": "^1.5.7",
|
|
54
54
|
"commander": "^14.0.0",
|
|
55
55
|
"esbuild": "^0.25.5",
|
|
56
|
-
"opnet": "^1.7.
|
|
56
|
+
"opnet": "^1.7.18",
|
|
57
57
|
"ora": "^8.2.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@eslint/js": "^9.39.1",
|
|
61
|
-
"@types/node": "^
|
|
61
|
+
"@types/node": "^25.0.2",
|
|
62
62
|
"eslint": "^9.39.1",
|
|
63
63
|
"gulp": "^5.0.1",
|
|
64
64
|
"gulp-cached": "^1.1.1",
|
|
@@ -164,6 +164,12 @@ export class InitCommand extends BaseCommand {
|
|
|
164
164
|
|
|
165
165
|
// Create README.md
|
|
166
166
|
this.createReadme(projectDir, config, force);
|
|
167
|
+
|
|
168
|
+
// Create ESLint config
|
|
169
|
+
this.createEslintConfig(projectDir, force);
|
|
170
|
+
|
|
171
|
+
// Create Prettier config
|
|
172
|
+
this.createPrettierConfig(projectDir, force);
|
|
167
173
|
}
|
|
168
174
|
|
|
169
175
|
private createPluginJson(
|
|
@@ -183,7 +189,6 @@ export class InitCommand extends BaseCommand {
|
|
|
183
189
|
main: 'dist/index.jsc',
|
|
184
190
|
target: 'bytenode',
|
|
185
191
|
type: 'plugin',
|
|
186
|
-
checksum: '',
|
|
187
192
|
author: config.authorEmail
|
|
188
193
|
? { name: config.authorName, email: config.authorEmail }
|
|
189
194
|
: { name: config.authorName },
|
|
@@ -277,9 +282,10 @@ export class InitCommand extends BaseCommand {
|
|
|
277
282
|
main: 'dist/index.js',
|
|
278
283
|
scripts: {
|
|
279
284
|
build: 'tsc',
|
|
280
|
-
compile: 'opnet compile',
|
|
281
|
-
verify: 'opnet verify',
|
|
285
|
+
compile: 'npx opnet compile',
|
|
286
|
+
verify: 'npx opnet verify',
|
|
282
287
|
lint: 'eslint src/',
|
|
288
|
+
format: 'prettier --write src/',
|
|
283
289
|
},
|
|
284
290
|
author: config.authorEmail
|
|
285
291
|
? `${config.authorName} <${config.authorEmail}>`
|
|
@@ -287,8 +293,12 @@ export class InitCommand extends BaseCommand {
|
|
|
287
293
|
license: 'Apache-2.0',
|
|
288
294
|
dependencies: { '@btc-vision/plugin-sdk': '^1.0.0' },
|
|
289
295
|
devDependencies: {
|
|
290
|
-
'@
|
|
296
|
+
'@eslint/js': '^9.39.0',
|
|
297
|
+
'@types/node': '^25.0.0',
|
|
298
|
+
eslint: '^9.39.0',
|
|
299
|
+
prettier: '^3.6.0',
|
|
291
300
|
typescript: '^5.8.0',
|
|
301
|
+
'typescript-eslint': '^8.39.0',
|
|
292
302
|
'@btc-vision/cli': '^1.0.0',
|
|
293
303
|
},
|
|
294
304
|
};
|
|
@@ -454,6 +464,78 @@ Apache-2.0
|
|
|
454
464
|
this.logger.success(' Created README.md');
|
|
455
465
|
}
|
|
456
466
|
|
|
467
|
+
private createEslintConfig(projectDir: string, force?: boolean): void {
|
|
468
|
+
const eslintPath = path.join(projectDir, 'eslint.config.js');
|
|
469
|
+
if (fs.existsSync(eslintPath) && !force) return;
|
|
470
|
+
|
|
471
|
+
const content = `// @ts-check
|
|
472
|
+
|
|
473
|
+
import eslint from '@eslint/js';
|
|
474
|
+
import tseslint from 'typescript-eslint';
|
|
475
|
+
|
|
476
|
+
export default tseslint.config(
|
|
477
|
+
eslint.configs.recommended,
|
|
478
|
+
...tseslint.configs.strictTypeChecked,
|
|
479
|
+
{
|
|
480
|
+
languageOptions: {
|
|
481
|
+
parserOptions: {
|
|
482
|
+
projectService: true,
|
|
483
|
+
tsconfigDirName: import.meta.dirname,
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
rules: {
|
|
487
|
+
'no-undef': 'off',
|
|
488
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
489
|
+
'no-empty': 'off',
|
|
490
|
+
'@typescript-eslint/restrict-template-expressions': 'off',
|
|
491
|
+
'@typescript-eslint/only-throw-error': 'off',
|
|
492
|
+
'@typescript-eslint/no-unnecessary-condition': 'off',
|
|
493
|
+
'@typescript-eslint/unbound-method': 'warn',
|
|
494
|
+
'@typescript-eslint/no-confusing-void-expression': 'off',
|
|
495
|
+
'@typescript-eslint/no-extraneous-class': 'off',
|
|
496
|
+
'no-async-promise-executor': 'off',
|
|
497
|
+
'@typescript-eslint/no-misused-promises': 'off',
|
|
498
|
+
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
|
|
499
|
+
'@typescript-eslint/no-duplicate-enum-values': 'off',
|
|
500
|
+
'prefer-spread': 'off',
|
|
501
|
+
'@typescript-eslint/no-empty-object-type': 'off',
|
|
502
|
+
'@typescript-eslint/no-base-to-string': 'off',
|
|
503
|
+
'@typescript-eslint/no-dynamic-delete': 'off',
|
|
504
|
+
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
files: ['**/*.js'],
|
|
509
|
+
...tseslint.configs.disableTypeChecked,
|
|
510
|
+
},
|
|
511
|
+
);
|
|
512
|
+
`;
|
|
513
|
+
|
|
514
|
+
fs.writeFileSync(eslintPath, content);
|
|
515
|
+
this.logger.success(' Created eslint.config.js');
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
private createPrettierConfig(projectDir: string, force?: boolean): void {
|
|
519
|
+
const prettierPath = path.join(projectDir, '.prettierrc.json');
|
|
520
|
+
if (fs.existsSync(prettierPath) && !force) return;
|
|
521
|
+
|
|
522
|
+
const config = {
|
|
523
|
+
printWidth: 100,
|
|
524
|
+
trailingComma: 'all',
|
|
525
|
+
tabWidth: 4,
|
|
526
|
+
semi: true,
|
|
527
|
+
singleQuote: true,
|
|
528
|
+
quoteProps: 'as-needed',
|
|
529
|
+
bracketSpacing: true,
|
|
530
|
+
bracketSameLine: true,
|
|
531
|
+
arrowParens: 'always',
|
|
532
|
+
singleAttributePerLine: true,
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
fs.writeFileSync(prettierPath, JSON.stringify(config, null, 4));
|
|
536
|
+
this.logger.success(' Created .prettierrc.json');
|
|
537
|
+
}
|
|
538
|
+
|
|
457
539
|
private toPascalCase(str: string): string {
|
|
458
540
|
return str
|
|
459
541
|
.split(/[-_]/)
|
package/src/lib/config.ts
CHANGED
|
@@ -10,7 +10,6 @@ import * as fs from 'fs';
|
|
|
10
10
|
import * as path from 'path';
|
|
11
11
|
import * as os from 'os';
|
|
12
12
|
import { CLIConfig, CLIMldsaLevel, NetworkName } from '../types/index.js';
|
|
13
|
-
import { Address } from '@btc-vision/transaction';
|
|
14
13
|
|
|
15
14
|
/** Default configuration directory */
|
|
16
15
|
const CONFIG_DIR = path.join(os.homedir(), '.opnet');
|
|
@@ -38,9 +37,9 @@ const DEFAULT_CONFIG: CLIConfig = {
|
|
|
38
37
|
ipfsPinningApiKey: '',
|
|
39
38
|
ipfsPinningAuthHeader: 'Authorization',
|
|
40
39
|
registryAddresses: {
|
|
41
|
-
mainnet:
|
|
42
|
-
testnet:
|
|
43
|
-
regtest:
|
|
40
|
+
mainnet: '', // TODO: Set once deployed
|
|
41
|
+
testnet: '', // TODO: Set once deployed
|
|
42
|
+
regtest: '', // TODO: Set once deployed
|
|
44
43
|
},
|
|
45
44
|
defaultMldsaLevel: 44,
|
|
46
45
|
indexerUrl: 'https://indexer.opnet.org',
|
package/src/lib/ipfs.ts
CHANGED
package/src/lib/manifest.ts
CHANGED
|
@@ -89,6 +89,10 @@ export function validatePermissions(permissions: IPluginPermissions): string[] {
|
|
|
89
89
|
/**
|
|
90
90
|
* Load and validate a plugin manifest from file
|
|
91
91
|
*
|
|
92
|
+
* Note: This performs basic validation suitable for source manifests.
|
|
93
|
+
* The SDK's strict validation requires fields like 'checksum' which
|
|
94
|
+
* are only computed during compilation, not in source plugin.json.
|
|
95
|
+
*
|
|
92
96
|
* @param manifestPath - Path to plugin.json
|
|
93
97
|
* @returns The loaded manifest or throws with validation errors
|
|
94
98
|
*/
|
|
@@ -107,13 +111,33 @@ export function loadManifest(manifestPath: string): IPluginMetadata {
|
|
|
107
111
|
throw new Error(`Failed to parse manifest: ${e instanceof Error ? e.message : String(e)}`);
|
|
108
112
|
}
|
|
109
113
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
// Basic validation for source manifests (checksum is computed during compilation)
|
|
115
|
+
const errors: string[] = [];
|
|
116
|
+
if (!manifest.name || typeof manifest.name !== 'string') {
|
|
117
|
+
errors.push('name is required');
|
|
118
|
+
}
|
|
119
|
+
if (!manifest.version || typeof manifest.version !== 'string') {
|
|
120
|
+
errors.push('version is required');
|
|
121
|
+
}
|
|
122
|
+
if (!manifest.author || typeof manifest.author !== 'object') {
|
|
123
|
+
errors.push('author is required');
|
|
124
|
+
}
|
|
125
|
+
if (!manifest.pluginType || !['standalone', 'library'].includes(manifest.pluginType)) {
|
|
126
|
+
errors.push('pluginType must be "standalone" or "library"');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (errors.length > 0) {
|
|
130
|
+
throw new Error(`Invalid manifest:\n${errors.map((e) => ` - ${e}`).join('\n')}`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Set default checksum for compilation (will be computed)
|
|
134
|
+
// Cast to mutable to allow setting checksum
|
|
135
|
+
const result = manifest as { -readonly [K in keyof IPluginMetadata]: IPluginMetadata[K] };
|
|
136
|
+
if (!result.checksum) {
|
|
137
|
+
result.checksum = '';
|
|
114
138
|
}
|
|
115
139
|
|
|
116
|
-
return
|
|
140
|
+
return result as IPluginMetadata;
|
|
117
141
|
}
|
|
118
142
|
|
|
119
143
|
/**
|
|
@@ -139,7 +163,7 @@ export function createManifest(options: {
|
|
|
139
163
|
email?: string;
|
|
140
164
|
description?: string;
|
|
141
165
|
pluginType: 'standalone' | 'library';
|
|
142
|
-
}): IPluginMetadata {
|
|
166
|
+
}): Omit<IPluginMetadata, 'checksum'> {
|
|
143
167
|
return {
|
|
144
168
|
name: options.name,
|
|
145
169
|
version: '1.0.0',
|
|
@@ -147,7 +171,6 @@ export function createManifest(options: {
|
|
|
147
171
|
main: 'dist/index.jsc',
|
|
148
172
|
target: 'bytenode',
|
|
149
173
|
type: 'plugin',
|
|
150
|
-
checksum: '',
|
|
151
174
|
author: {
|
|
152
175
|
name: options.author,
|
|
153
176
|
email: options.email,
|