@originals/sdk 1.8.1 → 1.8.2
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/dist/utils/hash.js +1 -0
- package/package.json +6 -5
- package/src/adapters/FeeOracleMock.ts +9 -0
- package/src/adapters/index.ts +5 -0
- package/src/adapters/providers/OrdHttpProvider.ts +126 -0
- package/src/adapters/providers/OrdMockProvider.ts +101 -0
- package/src/adapters/types.ts +66 -0
- package/src/bitcoin/BitcoinManager.ts +329 -0
- package/src/bitcoin/BroadcastClient.ts +54 -0
- package/src/bitcoin/OrdinalsClient.ts +120 -0
- package/src/bitcoin/PSBTBuilder.ts +106 -0
- package/src/bitcoin/fee-calculation.ts +38 -0
- package/src/bitcoin/providers/OrdNodeProvider.ts +92 -0
- package/src/bitcoin/providers/OrdinalsProvider.ts +56 -0
- package/src/bitcoin/providers/types.ts +59 -0
- package/src/bitcoin/transactions/commit.ts +465 -0
- package/src/bitcoin/transactions/index.ts +13 -0
- package/src/bitcoin/transfer.ts +43 -0
- package/src/bitcoin/utxo-selection.ts +322 -0
- package/src/bitcoin/utxo.ts +113 -0
- package/src/cel/ExternalReferenceManager.ts +87 -0
- package/src/cel/OriginalsCel.ts +460 -0
- package/src/cel/algorithms/createEventLog.ts +68 -0
- package/src/cel/algorithms/deactivateEventLog.ts +109 -0
- package/src/cel/algorithms/index.ts +11 -0
- package/src/cel/algorithms/updateEventLog.ts +99 -0
- package/src/cel/algorithms/verifyEventLog.ts +306 -0
- package/src/cel/algorithms/witnessEvent.ts +87 -0
- package/src/cel/cli/create.ts +330 -0
- package/src/cel/cli/index.ts +383 -0
- package/src/cel/cli/inspect.ts +549 -0
- package/src/cel/cli/migrate.ts +473 -0
- package/src/cel/cli/verify.ts +249 -0
- package/src/cel/hash.ts +71 -0
- package/src/cel/index.ts +16 -0
- package/src/cel/layers/BtcoCelManager.ts +408 -0
- package/src/cel/layers/PeerCelManager.ts +371 -0
- package/src/cel/layers/WebVHCelManager.ts +361 -0
- package/src/cel/layers/index.ts +27 -0
- package/src/cel/serialization/cbor.ts +189 -0
- package/src/cel/serialization/index.ts +10 -0
- package/src/cel/serialization/json.ts +209 -0
- package/src/cel/types.ts +160 -0
- package/src/cel/witnesses/BitcoinWitness.ts +184 -0
- package/src/cel/witnesses/HttpWitness.ts +241 -0
- package/src/cel/witnesses/WitnessService.ts +51 -0
- package/src/cel/witnesses/index.ts +11 -0
- package/src/contexts/credentials-v1.json +237 -0
- package/src/contexts/credentials-v2-examples.json +5 -0
- package/src/contexts/credentials-v2.json +340 -0
- package/src/contexts/credentials.json +237 -0
- package/src/contexts/data-integrity-v2.json +81 -0
- package/src/contexts/dids.json +58 -0
- package/src/contexts/ed255192020.json +93 -0
- package/src/contexts/ordinals-plus.json +23 -0
- package/src/contexts/originals.json +22 -0
- package/src/core/OriginalsSDK.ts +420 -0
- package/src/crypto/Multikey.ts +194 -0
- package/src/crypto/Signer.ts +262 -0
- package/src/crypto/noble-init.ts +138 -0
- package/src/did/BtcoDidResolver.ts +231 -0
- package/src/did/DIDManager.ts +705 -0
- package/src/did/Ed25519Verifier.ts +68 -0
- package/src/did/KeyManager.ts +239 -0
- package/src/did/WebVHManager.ts +499 -0
- package/src/did/createBtcoDidDocument.ts +60 -0
- package/src/did/providers/OrdinalsClientProviderAdapter.ts +68 -0
- package/src/events/EventEmitter.ts +222 -0
- package/src/events/index.ts +19 -0
- package/src/events/types.ts +331 -0
- package/src/examples/basic-usage.ts +78 -0
- package/src/examples/create-module-original.ts +435 -0
- package/src/examples/full-lifecycle-flow.ts +514 -0
- package/src/examples/run.ts +60 -0
- package/src/index.ts +204 -0
- package/src/kinds/KindRegistry.ts +320 -0
- package/src/kinds/index.ts +74 -0
- package/src/kinds/types.ts +470 -0
- package/src/kinds/validators/AgentValidator.ts +257 -0
- package/src/kinds/validators/AppValidator.ts +211 -0
- package/src/kinds/validators/DatasetValidator.ts +242 -0
- package/src/kinds/validators/DocumentValidator.ts +311 -0
- package/src/kinds/validators/MediaValidator.ts +269 -0
- package/src/kinds/validators/ModuleValidator.ts +225 -0
- package/src/kinds/validators/base.ts +276 -0
- package/src/kinds/validators/index.ts +12 -0
- package/src/lifecycle/BatchOperations.ts +381 -0
- package/src/lifecycle/LifecycleManager.ts +2156 -0
- package/src/lifecycle/OriginalsAsset.ts +524 -0
- package/src/lifecycle/ProvenanceQuery.ts +280 -0
- package/src/lifecycle/ResourceVersioning.ts +163 -0
- package/src/migration/MigrationManager.ts +587 -0
- package/src/migration/audit/AuditLogger.ts +176 -0
- package/src/migration/checkpoint/CheckpointManager.ts +112 -0
- package/src/migration/checkpoint/CheckpointStorage.ts +101 -0
- package/src/migration/index.ts +33 -0
- package/src/migration/operations/BaseMigration.ts +126 -0
- package/src/migration/operations/PeerToBtcoMigration.ts +105 -0
- package/src/migration/operations/PeerToWebvhMigration.ts +62 -0
- package/src/migration/operations/WebvhToBtcoMigration.ts +105 -0
- package/src/migration/rollback/RollbackManager.ts +170 -0
- package/src/migration/state/StateMachine.ts +92 -0
- package/src/migration/state/StateTracker.ts +156 -0
- package/src/migration/types.ts +356 -0
- package/src/migration/validation/BitcoinValidator.ts +107 -0
- package/src/migration/validation/CredentialValidator.ts +62 -0
- package/src/migration/validation/DIDCompatibilityValidator.ts +151 -0
- package/src/migration/validation/LifecycleValidator.ts +64 -0
- package/src/migration/validation/StorageValidator.ts +79 -0
- package/src/migration/validation/ValidationPipeline.ts +213 -0
- package/src/resources/ResourceManager.ts +655 -0
- package/src/resources/index.ts +21 -0
- package/src/resources/types.ts +202 -0
- package/src/storage/LocalStorageAdapter.ts +64 -0
- package/src/storage/MemoryStorageAdapter.ts +29 -0
- package/src/storage/StorageAdapter.ts +25 -0
- package/src/storage/index.ts +3 -0
- package/src/types/bitcoin.ts +98 -0
- package/src/types/common.ts +92 -0
- package/src/types/credentials.ts +89 -0
- package/src/types/did.ts +31 -0
- package/src/types/external-shims.d.ts +53 -0
- package/src/types/index.ts +7 -0
- package/src/types/network.ts +178 -0
- package/src/utils/EventLogger.ts +298 -0
- package/src/utils/Logger.ts +324 -0
- package/src/utils/MetricsCollector.ts +358 -0
- package/src/utils/bitcoin-address.ts +132 -0
- package/src/utils/cbor.ts +31 -0
- package/src/utils/encoding.ts +135 -0
- package/src/utils/hash.ts +12 -0
- package/src/utils/retry.ts +46 -0
- package/src/utils/satoshi-validation.ts +196 -0
- package/src/utils/serialization.ts +102 -0
- package/src/utils/telemetry.ts +44 -0
- package/src/utils/validation.ts +123 -0
- package/src/vc/CredentialManager.ts +955 -0
- package/src/vc/Issuer.ts +105 -0
- package/src/vc/Verifier.ts +54 -0
- package/src/vc/cryptosuites/bbs.ts +253 -0
- package/src/vc/cryptosuites/bbsSimple.ts +21 -0
- package/src/vc/cryptosuites/eddsa.ts +99 -0
- package/src/vc/documentLoader.ts +81 -0
- package/src/vc/proofs/data-integrity.ts +33 -0
- package/src/vc/utils/jsonld.ts +18 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI Migrate Command
|
|
4
|
+
*
|
|
5
|
+
* Migrates a CEL asset between layers in the Originals Protocol.
|
|
6
|
+
*
|
|
7
|
+
* Migration paths:
|
|
8
|
+
* - peer → webvh: Requires --domain
|
|
9
|
+
* - webvh → btco: Requires --wallet
|
|
10
|
+
*
|
|
11
|
+
* Usage: originals-cel migrate --log <path> --to <layer> [options]
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import * as fs from 'fs';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
import type { EventLog, DataIntegrityProof } from '../types';
|
|
17
|
+
import { WebVHCelManager } from '../layers/WebVHCelManager';
|
|
18
|
+
import { BtcoCelManager } from '../layers/BtcoCelManager';
|
|
19
|
+
import type { CelSigner } from '../layers/PeerCelManager';
|
|
20
|
+
import { parseEventLogJson } from '../serialization/json';
|
|
21
|
+
import { parseEventLogCbor } from '../serialization/cbor';
|
|
22
|
+
import { serializeEventLogJson } from '../serialization/json';
|
|
23
|
+
import { serializeEventLogCbor } from '../serialization/cbor';
|
|
24
|
+
import { multikey } from '../../crypto/Multikey';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Flags parsed from command line arguments
|
|
28
|
+
*/
|
|
29
|
+
export interface MigrateFlags {
|
|
30
|
+
log?: string;
|
|
31
|
+
to?: string;
|
|
32
|
+
domain?: string;
|
|
33
|
+
wallet?: string;
|
|
34
|
+
output?: string;
|
|
35
|
+
format?: string;
|
|
36
|
+
help?: boolean;
|
|
37
|
+
h?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Result of the migrate command
|
|
42
|
+
*/
|
|
43
|
+
export interface MigrateResult {
|
|
44
|
+
success: boolean;
|
|
45
|
+
message: string;
|
|
46
|
+
log?: EventLog;
|
|
47
|
+
sourceDid?: string;
|
|
48
|
+
targetDid?: string;
|
|
49
|
+
targetLayer?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Valid target layers for migration
|
|
54
|
+
*/
|
|
55
|
+
const VALID_LAYERS = ['webvh', 'btco'] as const;
|
|
56
|
+
type TargetLayer = typeof VALID_LAYERS[number];
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Loads and parses an event log from a file
|
|
60
|
+
* Supports both JSON (.json) and CBOR (.cbor) formats
|
|
61
|
+
*/
|
|
62
|
+
function loadEventLog(filePath: string): EventLog {
|
|
63
|
+
if (!fs.existsSync(filePath)) {
|
|
64
|
+
throw new Error(`File not found: ${filePath}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
68
|
+
const content = fs.readFileSync(filePath);
|
|
69
|
+
|
|
70
|
+
if (ext === '.cbor') {
|
|
71
|
+
// Parse as CBOR binary
|
|
72
|
+
return parseEventLogCbor(new Uint8Array(content));
|
|
73
|
+
} else {
|
|
74
|
+
// Default to JSON parsing
|
|
75
|
+
return parseEventLogJson(content.toString('utf-8'));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Detects the current layer from an event log by examining events
|
|
81
|
+
*/
|
|
82
|
+
function detectCurrentLayer(log: EventLog): 'peer' | 'webvh' | 'btco' {
|
|
83
|
+
if (!log.events || log.events.length === 0) {
|
|
84
|
+
throw new Error('Cannot detect layer from empty event log');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let currentLayer: 'peer' | 'webvh' | 'btco' = 'peer';
|
|
88
|
+
|
|
89
|
+
for (const event of log.events) {
|
|
90
|
+
const data = event.data as Record<string, unknown>;
|
|
91
|
+
|
|
92
|
+
if (event.type === 'create' && data.layer) {
|
|
93
|
+
currentLayer = data.layer as 'peer' | 'webvh' | 'btco';
|
|
94
|
+
} else if (event.type === 'update' && data.layer && data.targetDid) {
|
|
95
|
+
// This is a migration event
|
|
96
|
+
currentLayer = data.layer as 'peer' | 'webvh' | 'btco';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return currentLayer;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Extracts the current DID from an event log
|
|
105
|
+
*/
|
|
106
|
+
function getCurrentDid(log: EventLog): string {
|
|
107
|
+
if (!log.events || log.events.length === 0) {
|
|
108
|
+
throw new Error('Cannot extract DID from empty event log');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let currentDid: string | undefined;
|
|
112
|
+
|
|
113
|
+
for (const event of log.events) {
|
|
114
|
+
const data = event.data as Record<string, unknown>;
|
|
115
|
+
|
|
116
|
+
if (event.type === 'create' && data.did) {
|
|
117
|
+
currentDid = data.did as string;
|
|
118
|
+
} else if (event.type === 'update' && data.targetDid) {
|
|
119
|
+
// This is a migration event
|
|
120
|
+
currentDid = data.targetDid as string;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!currentDid) {
|
|
125
|
+
throw new Error('Could not determine current DID from event log');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return currentDid;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Validates the migration path
|
|
133
|
+
*/
|
|
134
|
+
function validateMigrationPath(currentLayer: string, targetLayer: TargetLayer): void {
|
|
135
|
+
if (currentLayer === 'btco') {
|
|
136
|
+
throw new Error('Cannot migrate from btco layer - it is the final layer');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (currentLayer === 'peer' && targetLayer === 'btco') {
|
|
140
|
+
throw new Error('Cannot migrate directly from peer to btco. Must migrate to webvh first.');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (currentLayer === 'webvh' && targetLayer === 'webvh') {
|
|
144
|
+
throw new Error('Asset is already at webvh layer');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (currentLayer === targetLayer) {
|
|
148
|
+
throw new Error(`Asset is already at ${targetLayer} layer`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Loads an Ed25519 private key from a wallet file
|
|
154
|
+
* Supports both raw multibase format and JSON format { privateKey: "z..." }
|
|
155
|
+
*/
|
|
156
|
+
async function loadWalletKey(walletPath: string): Promise<{ privateKey: string; publicKey: string }> {
|
|
157
|
+
if (!fs.existsSync(walletPath)) {
|
|
158
|
+
throw new Error(`Wallet file not found: ${walletPath}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const content = fs.readFileSync(walletPath, 'utf-8').trim();
|
|
162
|
+
|
|
163
|
+
let privateKey: string;
|
|
164
|
+
|
|
165
|
+
// Try parsing as JSON first
|
|
166
|
+
try {
|
|
167
|
+
const parsed = JSON.parse(content);
|
|
168
|
+
if (parsed.privateKey) {
|
|
169
|
+
privateKey = parsed.privateKey;
|
|
170
|
+
} else {
|
|
171
|
+
throw new Error('JSON wallet file must contain "privateKey" field');
|
|
172
|
+
}
|
|
173
|
+
} catch (e) {
|
|
174
|
+
// Not JSON, treat as raw multibase key
|
|
175
|
+
if (content.startsWith('z')) {
|
|
176
|
+
privateKey = content;
|
|
177
|
+
} else {
|
|
178
|
+
throw new Error('Wallet file must contain a z-base58btc multibase-encoded Ed25519 private key');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Validate and decode to get public key
|
|
183
|
+
const decoded = multikey.decodePrivateKey(privateKey);
|
|
184
|
+
if (decoded.type !== 'Ed25519') {
|
|
185
|
+
throw new Error(`Expected Ed25519 key, got ${decoded.type}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Derive public key from private key
|
|
189
|
+
const ed25519 = await import('@noble/ed25519');
|
|
190
|
+
const publicKeyBytes = await (ed25519 as any).getPublicKeyAsync(decoded.key);
|
|
191
|
+
const publicKey = multikey.encodePublicKey(publicKeyBytes as Uint8Array, 'Ed25519');
|
|
192
|
+
|
|
193
|
+
return { privateKey, publicKey };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Creates a signer function from a private key
|
|
198
|
+
*/
|
|
199
|
+
function createSigner(privateKey: string, publicKey: string): CelSigner {
|
|
200
|
+
return async (data: unknown): Promise<DataIntegrityProof> => {
|
|
201
|
+
const ed25519 = await import('@noble/ed25519');
|
|
202
|
+
const decoded = multikey.decodePrivateKey(privateKey);
|
|
203
|
+
|
|
204
|
+
// Serialize data for signing (deterministic JSON)
|
|
205
|
+
const dataStr = JSON.stringify(data, Object.keys(data as object).sort());
|
|
206
|
+
const dataBytes = new TextEncoder().encode(dataStr);
|
|
207
|
+
|
|
208
|
+
// Sign the data
|
|
209
|
+
const signature = await (ed25519 as any).signAsync(dataBytes, decoded.key);
|
|
210
|
+
const proofValue = multikey.encodeMultibase(new Uint8Array(signature));
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
type: 'DataIntegrityProof',
|
|
214
|
+
cryptosuite: 'eddsa-jcs-2022',
|
|
215
|
+
created: new Date().toISOString(),
|
|
216
|
+
verificationMethod: `did:key:${publicKey}#${publicKey}`,
|
|
217
|
+
proofPurpose: 'assertionMethod',
|
|
218
|
+
proofValue,
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Creates a mock BitcoinManager for testing/development
|
|
225
|
+
* In production, this would be a real BitcoinManager instance
|
|
226
|
+
*/
|
|
227
|
+
function createMockBitcoinManager(): any {
|
|
228
|
+
// For CLI use, we create a minimal mock that satisfies the interface
|
|
229
|
+
// Real Bitcoin integration requires additional configuration
|
|
230
|
+
return {
|
|
231
|
+
inscribeData: async (data: unknown) => {
|
|
232
|
+
// Generate mock Bitcoin transaction details
|
|
233
|
+
const timestamp = Date.now();
|
|
234
|
+
const mockTxid = `cli_mock_tx_${timestamp.toString(16)}`;
|
|
235
|
+
const mockInscriptionId = `cli_mock_inscription_${timestamp.toString(16)}i0`;
|
|
236
|
+
|
|
237
|
+
console.error('\n⚠️ Note: Using mock Bitcoin manager for CLI migration.');
|
|
238
|
+
console.error(' For real Bitcoin inscriptions, use the SDK programmatically.\n');
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
txid: mockTxid,
|
|
242
|
+
inscriptionId: mockInscriptionId,
|
|
243
|
+
satoshi: 10000,
|
|
244
|
+
blockHeight: 0, // Will be set when confirmed
|
|
245
|
+
};
|
|
246
|
+
},
|
|
247
|
+
getInscription: async (inscriptionId: string) => {
|
|
248
|
+
return { inscriptionId, confirmed: false };
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Execute the migrate command
|
|
255
|
+
*/
|
|
256
|
+
export async function migrateCommand(flags: MigrateFlags): Promise<MigrateResult> {
|
|
257
|
+
// Check for help flag
|
|
258
|
+
if (flags.help || flags.h) {
|
|
259
|
+
return {
|
|
260
|
+
success: true,
|
|
261
|
+
message: 'Use --help with the main CLI for full help text',
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Validate required arguments
|
|
266
|
+
if (!flags.log) {
|
|
267
|
+
return {
|
|
268
|
+
success: false,
|
|
269
|
+
message: 'Error: --log is required. Usage: originals-cel migrate --log <path> --to <layer>',
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (!flags.to) {
|
|
274
|
+
return {
|
|
275
|
+
success: false,
|
|
276
|
+
message: 'Error: --to is required. Valid layers: webvh, btco',
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Validate target layer
|
|
281
|
+
const targetLayer = flags.to.toLowerCase() as TargetLayer;
|
|
282
|
+
if (!VALID_LAYERS.includes(targetLayer)) {
|
|
283
|
+
return {
|
|
284
|
+
success: false,
|
|
285
|
+
message: `Error: Invalid target layer "${flags.to}". Valid layers: webvh, btco`,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Validate layer-specific requirements
|
|
290
|
+
if (targetLayer === 'webvh' && !flags.domain) {
|
|
291
|
+
return {
|
|
292
|
+
success: false,
|
|
293
|
+
message: 'Error: --domain is required for webvh migration. Usage: originals-cel migrate --log <path> --to webvh --domain example.com',
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (targetLayer === 'btco' && !flags.wallet) {
|
|
298
|
+
return {
|
|
299
|
+
success: false,
|
|
300
|
+
message: 'Error: --wallet is required for btco migration. Usage: originals-cel migrate --log <path> --to btco --wallet ./wallet.key',
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Load the event log
|
|
305
|
+
let eventLog: EventLog;
|
|
306
|
+
try {
|
|
307
|
+
eventLog = loadEventLog(flags.log);
|
|
308
|
+
} catch (e) {
|
|
309
|
+
return {
|
|
310
|
+
success: false,
|
|
311
|
+
message: `Error: Failed to load event log: ${(e as Error).message}`,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Detect current layer and validate migration path
|
|
316
|
+
let currentLayer: 'peer' | 'webvh' | 'btco';
|
|
317
|
+
try {
|
|
318
|
+
currentLayer = detectCurrentLayer(eventLog);
|
|
319
|
+
validateMigrationPath(currentLayer, targetLayer);
|
|
320
|
+
} catch (e) {
|
|
321
|
+
return {
|
|
322
|
+
success: false,
|
|
323
|
+
message: `Error: Invalid migration path: ${(e as Error).message}`,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Get source DID
|
|
328
|
+
let sourceDid: string;
|
|
329
|
+
try {
|
|
330
|
+
sourceDid = getCurrentDid(eventLog);
|
|
331
|
+
} catch (e) {
|
|
332
|
+
return {
|
|
333
|
+
success: false,
|
|
334
|
+
message: `Error: ${(e as Error).message}`,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Load wallet key for signing
|
|
339
|
+
let privateKey: string;
|
|
340
|
+
let publicKey: string;
|
|
341
|
+
|
|
342
|
+
if (flags.wallet) {
|
|
343
|
+
try {
|
|
344
|
+
const loaded = await loadWalletKey(flags.wallet);
|
|
345
|
+
privateKey = loaded.privateKey;
|
|
346
|
+
publicKey = loaded.publicKey;
|
|
347
|
+
} catch (e) {
|
|
348
|
+
return {
|
|
349
|
+
success: false,
|
|
350
|
+
message: `Error: Failed to load wallet: ${(e as Error).message}`,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
} else {
|
|
354
|
+
// Generate temporary key for signing (for webvh migration without wallet)
|
|
355
|
+
const ed25519 = await import('@noble/ed25519');
|
|
356
|
+
const privateKeyBytes = ed25519.utils.randomPrivateKey();
|
|
357
|
+
const publicKeyBytes = await (ed25519 as any).getPublicKeyAsync(privateKeyBytes);
|
|
358
|
+
privateKey = multikey.encodePrivateKey(privateKeyBytes as Uint8Array, 'Ed25519');
|
|
359
|
+
publicKey = multikey.encodePublicKey(publicKeyBytes as Uint8Array, 'Ed25519');
|
|
360
|
+
|
|
361
|
+
console.error('\n⚠️ Generated temporary signing key. Save the key below for future operations:');
|
|
362
|
+
console.error(`Private Key: ${privateKey}`);
|
|
363
|
+
console.error(`Public Key: ${publicKey}\n`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Create signer
|
|
367
|
+
const signer = createSigner(privateKey, publicKey);
|
|
368
|
+
|
|
369
|
+
// Perform migration
|
|
370
|
+
let migratedLog: EventLog;
|
|
371
|
+
let targetDid: string;
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
if (targetLayer === 'webvh') {
|
|
375
|
+
// Migrate to webvh layer
|
|
376
|
+
const manager = new WebVHCelManager(signer, flags.domain!, []);
|
|
377
|
+
migratedLog = await manager.migrate(eventLog);
|
|
378
|
+
|
|
379
|
+
// Extract target DID from migration event
|
|
380
|
+
const migrationEvent = migratedLog.events[migratedLog.events.length - 1];
|
|
381
|
+
const migrationData = migrationEvent.data as Record<string, unknown>;
|
|
382
|
+
targetDid = migrationData.targetDid as string;
|
|
383
|
+
|
|
384
|
+
} else if (targetLayer === 'btco') {
|
|
385
|
+
// Migrate to btco layer
|
|
386
|
+
const bitcoinManager = createMockBitcoinManager();
|
|
387
|
+
const manager = new BtcoCelManager(signer, bitcoinManager);
|
|
388
|
+
migratedLog = await manager.migrate(eventLog);
|
|
389
|
+
|
|
390
|
+
// Extract target DID from migration event
|
|
391
|
+
const migrationEvent = migratedLog.events[migratedLog.events.length - 1];
|
|
392
|
+
const migrationData = migrationEvent.data as Record<string, unknown>;
|
|
393
|
+
targetDid = migrationData.targetDid as string;
|
|
394
|
+
|
|
395
|
+
} else {
|
|
396
|
+
return {
|
|
397
|
+
success: false,
|
|
398
|
+
message: `Error: Unknown target layer: ${targetLayer}`,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
} catch (e) {
|
|
402
|
+
return {
|
|
403
|
+
success: false,
|
|
404
|
+
message: `Error: Migration failed: ${(e as Error).message}`,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Determine output format
|
|
409
|
+
const format = (flags.format || 'json').toLowerCase();
|
|
410
|
+
if (format !== 'json' && format !== 'cbor') {
|
|
411
|
+
return {
|
|
412
|
+
success: false,
|
|
413
|
+
message: 'Error: --format must be "json" or "cbor"',
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Serialize output
|
|
418
|
+
let output: string | Uint8Array;
|
|
419
|
+
try {
|
|
420
|
+
if (format === 'cbor') {
|
|
421
|
+
output = serializeEventLogCbor(migratedLog);
|
|
422
|
+
} else {
|
|
423
|
+
output = serializeEventLogJson(migratedLog);
|
|
424
|
+
}
|
|
425
|
+
} catch (e) {
|
|
426
|
+
return {
|
|
427
|
+
success: false,
|
|
428
|
+
message: `Error: Failed to serialize event log: ${(e as Error).message}`,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Write output
|
|
433
|
+
if (flags.output) {
|
|
434
|
+
try {
|
|
435
|
+
if (format === 'cbor') {
|
|
436
|
+
fs.writeFileSync(flags.output, output as Uint8Array);
|
|
437
|
+
} else {
|
|
438
|
+
fs.writeFileSync(flags.output, output as string, 'utf-8');
|
|
439
|
+
}
|
|
440
|
+
} catch (e) {
|
|
441
|
+
return {
|
|
442
|
+
success: false,
|
|
443
|
+
message: `Error: Failed to write output file: ${(e as Error).message}`,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
} else {
|
|
447
|
+
// Write to stdout
|
|
448
|
+
if (format === 'cbor') {
|
|
449
|
+
// For CBOR, output as base64 to stdout since it's binary
|
|
450
|
+
const base64 = Buffer.from(output as Uint8Array).toString('base64');
|
|
451
|
+
process.stdout.write(base64);
|
|
452
|
+
} else {
|
|
453
|
+
process.stdout.write(output as string);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Build success message
|
|
458
|
+
const layerTransition = `${currentLayer} → ${targetLayer}`;
|
|
459
|
+
const outputInfo = flags.output ? ` and saved to ${flags.output}` : '';
|
|
460
|
+
|
|
461
|
+
console.error(`\n✅ Migration complete: ${layerTransition}`);
|
|
462
|
+
console.error(` Source DID: ${sourceDid}`);
|
|
463
|
+
console.error(` Target DID: ${targetDid}${outputInfo}\n`);
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
success: true,
|
|
467
|
+
message: `Migration complete: ${layerTransition}`,
|
|
468
|
+
log: migratedLog,
|
|
469
|
+
sourceDid,
|
|
470
|
+
targetDid,
|
|
471
|
+
targetLayer,
|
|
472
|
+
};
|
|
473
|
+
}
|