@btc-vision/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/.gitattributes +2 -0
  2. package/.github/dependabot.yml +9 -0
  3. package/.github/workflows/ci.yml +48 -0
  4. package/.prettierrc.json +12 -0
  5. package/CONTRIBUTING.md +56 -0
  6. package/LICENSE +190 -0
  7. package/NOTICE +17 -0
  8. package/README.md +509 -0
  9. package/SECURITY.md +35 -0
  10. package/build/commands/AcceptCommand.d.ts +7 -0
  11. package/build/commands/AcceptCommand.js +110 -0
  12. package/build/commands/BaseCommand.d.ts +12 -0
  13. package/build/commands/BaseCommand.js +27 -0
  14. package/build/commands/CompileCommand.d.ts +7 -0
  15. package/build/commands/CompileCommand.js +138 -0
  16. package/build/commands/ConfigCommand.d.ts +17 -0
  17. package/build/commands/ConfigCommand.js +124 -0
  18. package/build/commands/DeprecateCommand.d.ts +7 -0
  19. package/build/commands/DeprecateCommand.js +112 -0
  20. package/build/commands/InfoCommand.d.ts +10 -0
  21. package/build/commands/InfoCommand.js +223 -0
  22. package/build/commands/InitCommand.d.ts +16 -0
  23. package/build/commands/InitCommand.js +336 -0
  24. package/build/commands/InstallCommand.d.ts +7 -0
  25. package/build/commands/InstallCommand.js +130 -0
  26. package/build/commands/KeygenCommand.d.ts +13 -0
  27. package/build/commands/KeygenCommand.js +133 -0
  28. package/build/commands/ListCommand.d.ts +7 -0
  29. package/build/commands/ListCommand.js +117 -0
  30. package/build/commands/LoginCommand.d.ts +9 -0
  31. package/build/commands/LoginCommand.js +139 -0
  32. package/build/commands/LogoutCommand.d.ts +7 -0
  33. package/build/commands/LogoutCommand.js +57 -0
  34. package/build/commands/PublishCommand.d.ts +7 -0
  35. package/build/commands/PublishCommand.js +163 -0
  36. package/build/commands/SearchCommand.d.ts +7 -0
  37. package/build/commands/SearchCommand.js +97 -0
  38. package/build/commands/SignCommand.d.ts +7 -0
  39. package/build/commands/SignCommand.js +80 -0
  40. package/build/commands/TransferCommand.d.ts +8 -0
  41. package/build/commands/TransferCommand.js +179 -0
  42. package/build/commands/UndeprecateCommand.d.ts +7 -0
  43. package/build/commands/UndeprecateCommand.js +95 -0
  44. package/build/commands/UpdateCommand.d.ts +7 -0
  45. package/build/commands/UpdateCommand.js +130 -0
  46. package/build/commands/VerifyCommand.d.ts +7 -0
  47. package/build/commands/VerifyCommand.js +167 -0
  48. package/build/commands/WhoamiCommand.d.ts +7 -0
  49. package/build/commands/WhoamiCommand.js +84 -0
  50. package/build/index.d.ts +2 -0
  51. package/build/index.js +64 -0
  52. package/build/lib/PackageRegistry.abi.d.ts +2 -0
  53. package/build/lib/PackageRegistry.abi.js +356 -0
  54. package/build/lib/binary.d.ts +16 -0
  55. package/build/lib/binary.js +165 -0
  56. package/build/lib/config.d.ts +11 -0
  57. package/build/lib/config.js +160 -0
  58. package/build/lib/credentials.d.ts +10 -0
  59. package/build/lib/credentials.js +89 -0
  60. package/build/lib/ipfs.d.ts +16 -0
  61. package/build/lib/ipfs.js +209 -0
  62. package/build/lib/manifest.d.ts +14 -0
  63. package/build/lib/manifest.js +88 -0
  64. package/build/lib/provider.d.ts +9 -0
  65. package/build/lib/provider.js +48 -0
  66. package/build/lib/registry.d.ts +58 -0
  67. package/build/lib/registry.js +197 -0
  68. package/build/lib/wallet.d.ts +32 -0
  69. package/build/lib/wallet.js +114 -0
  70. package/build/types/PackageRegistry.d.ts +177 -0
  71. package/build/types/PackageRegistry.js +1 -0
  72. package/build/types/index.d.ts +30 -0
  73. package/build/types/index.js +52 -0
  74. package/eslint.config.js +41 -0
  75. package/gulpfile.js +41 -0
  76. package/package.json +83 -0
  77. package/src/commands/AcceptCommand.ts +151 -0
  78. package/src/commands/BaseCommand.ts +59 -0
  79. package/src/commands/CompileCommand.ts +196 -0
  80. package/src/commands/ConfigCommand.ts +144 -0
  81. package/src/commands/DeprecateCommand.ts +156 -0
  82. package/src/commands/InfoCommand.ts +293 -0
  83. package/src/commands/InitCommand.ts +465 -0
  84. package/src/commands/InstallCommand.ts +179 -0
  85. package/src/commands/KeygenCommand.ts +157 -0
  86. package/src/commands/ListCommand.ts +169 -0
  87. package/src/commands/LoginCommand.ts +197 -0
  88. package/src/commands/LogoutCommand.ts +76 -0
  89. package/src/commands/PublishCommand.ts +230 -0
  90. package/src/commands/SearchCommand.ts +141 -0
  91. package/src/commands/SignCommand.ts +122 -0
  92. package/src/commands/TransferCommand.ts +235 -0
  93. package/src/commands/UndeprecateCommand.ts +134 -0
  94. package/src/commands/UpdateCommand.ts +200 -0
  95. package/src/commands/VerifyCommand.ts +228 -0
  96. package/src/commands/WhoamiCommand.ts +113 -0
  97. package/src/index.ts +86 -0
  98. package/src/lib/PackageRegistry.abi.json +765 -0
  99. package/src/lib/PackageRegistry.abi.ts +365 -0
  100. package/src/lib/binary.ts +336 -0
  101. package/src/lib/config.ts +265 -0
  102. package/src/lib/credentials.ts +176 -0
  103. package/src/lib/ipfs.ts +369 -0
  104. package/src/lib/manifest.ts +172 -0
  105. package/src/lib/provider.ts +121 -0
  106. package/src/lib/registry.ts +464 -0
  107. package/src/lib/wallet.ts +271 -0
  108. package/src/types/PackageRegistry.ts +344 -0
  109. package/src/types/index.ts +145 -0
  110. package/tsconfig.json +25 -0
@@ -0,0 +1,464 @@
1
+ /**
2
+ * Package Registry contract interactions for OPNet CLI
3
+ *
4
+ * Provides functions for interacting with the on-chain PackageRegistry contract.
5
+ *
6
+ * @module lib/registry
7
+ */
8
+
9
+ import { getContract } from 'opnet';
10
+ import { Address } from '@btc-vision/transaction';
11
+ import * as crypto from 'crypto';
12
+
13
+ import { CLIMldsaLevel, NetworkName, RegistryPluginType } from '../types/index.js';
14
+ import { IPluginPermissions } from '@btc-vision/plugin-sdk';
15
+ import { IPackageRegistry } from '../types/PackageRegistry.js';
16
+ import { getProvider, getRegistryContractAddress } from './provider.js';
17
+ import { getNetwork } from './wallet.js';
18
+ import { loadConfig } from './config.js';
19
+ import { PACKAGE_REGISTRY_ABI } from './PackageRegistry.abi.js';
20
+
21
+ /**
22
+ * Scope information
23
+ */
24
+ export interface ScopeInfo {
25
+ exists: boolean;
26
+ owner: Address;
27
+ createdAt: bigint;
28
+ }
29
+
30
+ /**
31
+ * Package information
32
+ */
33
+ export interface PackageInfo {
34
+ exists: boolean;
35
+ owner: Address;
36
+ createdAt: bigint;
37
+ versionCount: bigint;
38
+ latestVersion: string;
39
+ }
40
+
41
+ /**
42
+ * Version information
43
+ */
44
+ export interface VersionInfo {
45
+ exists: boolean;
46
+ ipfsCid: string;
47
+ checksum: Uint8Array;
48
+ sigHash: Uint8Array;
49
+ mldsaLevel: number;
50
+ opnetVersionRange: string;
51
+ pluginType: number;
52
+ permissionsHash: Uint8Array;
53
+ depsHash: Uint8Array;
54
+ publisher: Address;
55
+ publishedAt: bigint;
56
+ deprecated: boolean;
57
+ }
58
+
59
+ /**
60
+ * Pending transfer information
61
+ */
62
+ export interface PendingTransferInfo {
63
+ pendingOwner: Address;
64
+ initiatedAt: bigint;
65
+ }
66
+
67
+ /**
68
+ * Registry contract cache
69
+ */
70
+ const registryCache = new Map<string, IPackageRegistry>();
71
+
72
+ /**
73
+ * Get the registry contract instance
74
+ *
75
+ * @param network - Network name (defaults to configured default)
76
+ * @returns Contract instance
77
+ */
78
+ export function getRegistryContract(network?: NetworkName): IPackageRegistry {
79
+ const config = loadConfig();
80
+ const targetNetwork = network || config.defaultNetwork;
81
+ const cacheKey = targetNetwork;
82
+
83
+ const cached = registryCache.get(cacheKey);
84
+ if (cached) {
85
+ return cached;
86
+ }
87
+
88
+ const provider = getProvider(targetNetwork);
89
+ const registryAddress = getRegistryContractAddress(targetNetwork);
90
+ const bitcoinNetwork = getNetwork(targetNetwork);
91
+
92
+ const contract = getContract<IPackageRegistry>(
93
+ registryAddress,
94
+ PACKAGE_REGISTRY_ABI,
95
+ provider,
96
+ bitcoinNetwork,
97
+ );
98
+
99
+ registryCache.set(cacheKey, contract);
100
+ return contract;
101
+ }
102
+
103
+ /**
104
+ * Clear registry contract cache
105
+ */
106
+ export function clearRegistryCache(): void {
107
+ registryCache.clear();
108
+ }
109
+
110
+ /**
111
+ * Get scope information
112
+ *
113
+ * @param scopeName - The scope name (without @)
114
+ * @param network - Network name
115
+ * @returns Scope information or null if not found
116
+ */
117
+ export async function getScope(
118
+ scopeName: string,
119
+ network?: NetworkName,
120
+ ): Promise<ScopeInfo | null> {
121
+ const contract = getRegistryContract(network);
122
+ const result = await contract.getScope(scopeName);
123
+
124
+ if (!result.properties.exists) {
125
+ return null;
126
+ }
127
+
128
+ return {
129
+ exists: result.properties.exists,
130
+ owner: result.properties.owner,
131
+ createdAt: result.properties.createdAt,
132
+ };
133
+ }
134
+
135
+ /**
136
+ * Get scope owner
137
+ *
138
+ * @param scopeName - The scope name (without @)
139
+ * @param network - Network name
140
+ * @returns Owner address or null if scope doesn't exist
141
+ */
142
+ export async function getScopeOwner(
143
+ scopeName: string,
144
+ network?: NetworkName,
145
+ ): Promise<Address | null> {
146
+ const contract = getRegistryContract(network);
147
+ try {
148
+ const result = await contract.getScopeOwner(scopeName);
149
+ return result.properties.owner;
150
+ } catch {
151
+ return null;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Get package information
157
+ *
158
+ * @param packageName - The package name (with @ for scoped)
159
+ * @param network - Network name
160
+ * @returns Package information or null if not found
161
+ */
162
+ export async function getPackage(
163
+ packageName: string,
164
+ network?: NetworkName,
165
+ ): Promise<PackageInfo | null> {
166
+ const contract = getRegistryContract(network);
167
+ const result = await contract.getPackage(packageName);
168
+
169
+ if (!result.properties.exists) {
170
+ return null;
171
+ }
172
+
173
+ return {
174
+ exists: result.properties.exists,
175
+ owner: result.properties.owner,
176
+ createdAt: result.properties.createdAt,
177
+ versionCount: result.properties.versionCount,
178
+ latestVersion: result.properties.latestVersion,
179
+ };
180
+ }
181
+
182
+ /**
183
+ * Get package owner
184
+ *
185
+ * @param packageName - The package name
186
+ * @param network - Network name
187
+ * @returns Owner address or null if package doesn't exist
188
+ */
189
+ export async function getPackageOwner(
190
+ packageName: string,
191
+ network?: NetworkName,
192
+ ): Promise<Address | null> {
193
+ const contract = getRegistryContract(network);
194
+ try {
195
+ const result = await contract.getOwner(packageName);
196
+ return result.properties.owner;
197
+ } catch {
198
+ return null;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Get version information
204
+ *
205
+ * @param packageName - The package name
206
+ * @param version - The version string (semver)
207
+ * @param network - Network name
208
+ * @returns Version information or null if not found
209
+ */
210
+ export async function getVersion(
211
+ packageName: string,
212
+ version: string,
213
+ network?: NetworkName,
214
+ ): Promise<VersionInfo | null> {
215
+ const contract = getRegistryContract(network);
216
+ const result = await contract.getVersion(packageName, version);
217
+
218
+ if (!result.properties.exists) {
219
+ return null;
220
+ }
221
+
222
+ return {
223
+ exists: result.properties.exists,
224
+ ipfsCid: result.properties.ipfsCid,
225
+ checksum: result.properties.checksum,
226
+ sigHash: result.properties.sigHash,
227
+ mldsaLevel: result.properties.mldsaLevel,
228
+ opnetVersionRange: result.properties.opnetVersionRange,
229
+ pluginType: result.properties.pluginType,
230
+ permissionsHash: result.properties.permissionsHash,
231
+ depsHash: result.properties.depsHash,
232
+ publisher: result.properties.publisher,
233
+ publishedAt: result.properties.publishedAt,
234
+ deprecated: result.properties.deprecated,
235
+ };
236
+ }
237
+
238
+ /**
239
+ * Check if a version is deprecated
240
+ *
241
+ * @param packageName - The package name
242
+ * @param version - The version string
243
+ * @param network - Network name
244
+ * @returns True if deprecated
245
+ */
246
+ export async function isVersionDeprecated(
247
+ packageName: string,
248
+ version: string,
249
+ network?: NetworkName,
250
+ ): Promise<boolean> {
251
+ const contract = getRegistryContract(network);
252
+ const result = await contract.isDeprecated(packageName, version);
253
+ return result.properties.deprecated;
254
+ }
255
+
256
+ /**
257
+ * Check if a version is immutable (past 72-hour window)
258
+ *
259
+ * @param packageName - The package name
260
+ * @param version - The version string
261
+ * @param network - Network name
262
+ * @returns True if immutable
263
+ */
264
+ export async function isVersionImmutable(
265
+ packageName: string,
266
+ version: string,
267
+ network?: NetworkName,
268
+ ): Promise<boolean> {
269
+ const contract = getRegistryContract(network);
270
+ const result = await contract.isImmutable(packageName, version);
271
+ return result.properties.immutable;
272
+ }
273
+
274
+ /**
275
+ * Get pending package transfer
276
+ *
277
+ * @param packageName - The package name
278
+ * @param network - Network name
279
+ * @returns Pending transfer info or null
280
+ */
281
+ export async function getPendingTransfer(
282
+ packageName: string,
283
+ network?: NetworkName,
284
+ ): Promise<PendingTransferInfo | null> {
285
+ const contract = getRegistryContract(network);
286
+ try {
287
+ const result = await contract.getPendingTransfer(packageName);
288
+ const pendingOwner = result.properties.pendingOwner;
289
+
290
+ // Check if there's actually a pending transfer (address not zero)
291
+ if (!pendingOwner || pendingOwner.toString() === '0'.repeat(64)) {
292
+ return null;
293
+ }
294
+
295
+ return {
296
+ pendingOwner,
297
+ initiatedAt: result.properties.initiatedAt,
298
+ };
299
+ } catch {
300
+ return null;
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Get pending scope transfer
306
+ *
307
+ * @param scopeName - The scope name
308
+ * @param network - Network name
309
+ * @returns Pending transfer info or null
310
+ */
311
+ export async function getPendingScopeTransfer(
312
+ scopeName: string,
313
+ network?: NetworkName,
314
+ ): Promise<PendingTransferInfo | null> {
315
+ const contract = getRegistryContract(network);
316
+ try {
317
+ const result = await contract.getPendingScopeTransfer(scopeName);
318
+ const pendingOwner = result.properties.pendingOwner;
319
+
320
+ // Check if there's actually a pending transfer (address not zero)
321
+ if (!pendingOwner || pendingOwner.toString() === '0'.repeat(64)) {
322
+ return null;
323
+ }
324
+
325
+ return {
326
+ pendingOwner,
327
+ initiatedAt: result.properties.initiatedAt,
328
+ };
329
+ } catch {
330
+ return null;
331
+ }
332
+ }
333
+
334
+ /**
335
+ * Get treasury address
336
+ *
337
+ * @param network - Network name
338
+ * @returns Treasury address string
339
+ */
340
+ export async function getTreasuryAddress(network?: NetworkName): Promise<string> {
341
+ const contract = getRegistryContract(network);
342
+ const result = await contract.getTreasuryAddress();
343
+ return result.properties.treasuryAddress;
344
+ }
345
+
346
+ /**
347
+ * Get scope registration price
348
+ *
349
+ * @param network - Network name
350
+ * @returns Price in satoshis
351
+ */
352
+ export async function getScopePrice(network?: NetworkName): Promise<bigint> {
353
+ const contract = getRegistryContract(network);
354
+ const result = await contract.getScopePrice();
355
+ return result.properties.priceSats;
356
+ }
357
+
358
+ /**
359
+ * Get package registration price
360
+ *
361
+ * @param network - Network name
362
+ * @returns Price in satoshis
363
+ */
364
+ export async function getPackagePrice(network?: NetworkName): Promise<bigint> {
365
+ const contract = getRegistryContract(network);
366
+ const result = await contract.getPackagePrice();
367
+ return result.properties.priceSats;
368
+ }
369
+
370
+ /**
371
+ * Parse a package name into scope and name
372
+ *
373
+ * @param fullName - Full package name (e.g., "@scope/name" or "name")
374
+ * @returns Object with scope (or null) and name
375
+ */
376
+ export function parsePackageName(fullName: string): { scope: string | null; name: string } {
377
+ if (fullName.startsWith('@')) {
378
+ const slashIndex = fullName.indexOf('/');
379
+ if (slashIndex > 0) {
380
+ return {
381
+ scope: fullName.substring(1, slashIndex),
382
+ name: fullName.substring(slashIndex + 1),
383
+ };
384
+ }
385
+ }
386
+ return { scope: null, name: fullName };
387
+ }
388
+
389
+ /**
390
+ * Compute permissions hash from permissions object
391
+ *
392
+ * @param permissions - Plugin permissions
393
+ * @returns SHA-256 hash as Uint8Array
394
+ */
395
+ export function computePermissionsHash(permissions: IPluginPermissions | undefined): Uint8Array {
396
+ const json = JSON.stringify(permissions);
397
+ const hash = crypto.createHash('sha256').update(json).digest();
398
+ return new Uint8Array(hash);
399
+ }
400
+
401
+ /**
402
+ * Encode dependencies for publishing
403
+ *
404
+ * @param dependencies - Dependencies map { name: version }
405
+ * @returns Encoded dependencies as Uint8Array
406
+ */
407
+ export function encodeDependencies(dependencies: Record<string, string>): Uint8Array {
408
+ if (Object.keys(dependencies).length === 0) {
409
+ return new Uint8Array(0);
410
+ }
411
+
412
+ const json = JSON.stringify(dependencies);
413
+ return new Uint8Array(Buffer.from(json, 'utf-8'));
414
+ }
415
+
416
+ /**
417
+ * Convert registry MLDSA level (1, 2, 3) to actual level (44, 65, 87)
418
+ *
419
+ * @param registryLevel - Registry level (1, 2, 3)
420
+ * @returns MLDSA level (44, 65, 87)
421
+ */
422
+ export function registryToMldsaLevel(registryLevel: number): CLIMldsaLevel {
423
+ const levels: Record<number, CLIMldsaLevel> = {
424
+ 1: 44,
425
+ 2: 65,
426
+ 3: 87,
427
+ };
428
+ return levels[registryLevel] || 44;
429
+ }
430
+
431
+ /**
432
+ * Convert MLDSA level (44, 65, 87) to registry level (1, 2, 3)
433
+ *
434
+ * @param mldsaLevel - MLDSA level (44, 65, 87)
435
+ * @returns Registry level (1, 2, 3)
436
+ */
437
+ export function mldsaLevelToRegistry(mldsaLevel: CLIMldsaLevel): number {
438
+ const levels: Record<CLIMldsaLevel, number> = {
439
+ 44: 1,
440
+ 65: 2,
441
+ 87: 3,
442
+ };
443
+ return levels[mldsaLevel] || 1;
444
+ }
445
+
446
+ /**
447
+ * Convert registry plugin type (1, 2) to string
448
+ *
449
+ * @param registryType - Registry plugin type (1, 2)
450
+ * @returns Plugin type string
451
+ */
452
+ export function registryToPluginType(registryType: number): RegistryPluginType {
453
+ return registryType === 2 ? 'library' : 'standalone';
454
+ }
455
+
456
+ /**
457
+ * Convert plugin type string to registry value
458
+ *
459
+ * @param pluginType - Plugin type string
460
+ * @returns Registry plugin type (1, 2)
461
+ */
462
+ export function pluginTypeToRegistry(pluginType: RegistryPluginType): number {
463
+ return pluginType === 'library' ? 2 : 1;
464
+ }