@originals/sdk 1.2.0 → 1.4.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.
Files changed (244) hide show
  1. package/package.json +1 -1
  2. package/src/did/DIDManager.ts +1 -1
  3. package/src/did/WebVHManager.ts +11 -2
  4. package/src/examples/create-module-original.ts +435 -0
  5. package/src/examples/full-lifecycle-flow.ts +514 -0
  6. package/src/examples/run.ts +59 -4
  7. package/src/index.ts +69 -3
  8. package/src/kinds/KindRegistry.ts +290 -0
  9. package/src/kinds/index.ts +74 -0
  10. package/src/kinds/types.ts +470 -0
  11. package/src/kinds/validators/AgentValidator.ts +257 -0
  12. package/src/kinds/validators/AppValidator.ts +211 -0
  13. package/src/kinds/validators/DatasetValidator.ts +242 -0
  14. package/src/kinds/validators/DocumentValidator.ts +311 -0
  15. package/src/kinds/validators/MediaValidator.ts +269 -0
  16. package/src/kinds/validators/ModuleValidator.ts +225 -0
  17. package/src/kinds/validators/base.ts +276 -0
  18. package/src/kinds/validators/index.ts +12 -0
  19. package/src/lifecycle/LifecycleManager.ts +909 -1
  20. package/src/resources/ResourceManager.ts +655 -0
  21. package/src/resources/index.ts +21 -0
  22. package/src/resources/types.ts +202 -0
  23. package/src/types/common.ts +1 -1
  24. package/src/vc/CredentialManager.ts +647 -2
  25. package/tests/integration/createTypedOriginal.test.ts +379 -0
  26. package/tests/performance/BatchOperations.perf.test.ts +2 -2
  27. package/tests/unit/kinds/KindRegistry.test.ts +329 -0
  28. package/tests/unit/kinds/types.test.ts +409 -0
  29. package/tests/unit/kinds/validators.test.ts +651 -0
  30. package/tests/unit/lifecycle/LifecycleManager.cleanapi.test.ts +441 -0
  31. package/tests/unit/resources/ResourceManager.test.ts +740 -0
  32. package/tests/unit/vc/CredentialManager.helpers.test.ts +527 -0
  33. package/.turbo/turbo-build.log +0 -1
  34. package/dist/adapters/FeeOracleMock.d.ts +0 -6
  35. package/dist/adapters/FeeOracleMock.js +0 -8
  36. package/dist/adapters/index.d.ts +0 -4
  37. package/dist/adapters/index.js +0 -4
  38. package/dist/adapters/providers/OrdHttpProvider.d.ts +0 -56
  39. package/dist/adapters/providers/OrdHttpProvider.js +0 -110
  40. package/dist/adapters/providers/OrdMockProvider.d.ts +0 -70
  41. package/dist/adapters/providers/OrdMockProvider.js +0 -75
  42. package/dist/adapters/types.d.ts +0 -71
  43. package/dist/adapters/types.js +0 -1
  44. package/dist/bitcoin/BitcoinManager.d.ts +0 -15
  45. package/dist/bitcoin/BitcoinManager.js +0 -262
  46. package/dist/bitcoin/BroadcastClient.d.ts +0 -30
  47. package/dist/bitcoin/BroadcastClient.js +0 -35
  48. package/dist/bitcoin/OrdinalsClient.d.ts +0 -21
  49. package/dist/bitcoin/OrdinalsClient.js +0 -105
  50. package/dist/bitcoin/PSBTBuilder.d.ts +0 -24
  51. package/dist/bitcoin/PSBTBuilder.js +0 -80
  52. package/dist/bitcoin/fee-calculation.d.ts +0 -14
  53. package/dist/bitcoin/fee-calculation.js +0 -31
  54. package/dist/bitcoin/providers/OrdNodeProvider.d.ts +0 -38
  55. package/dist/bitcoin/providers/OrdNodeProvider.js +0 -67
  56. package/dist/bitcoin/providers/OrdinalsProvider.d.ts +0 -33
  57. package/dist/bitcoin/providers/OrdinalsProvider.js +0 -50
  58. package/dist/bitcoin/providers/types.d.ts +0 -63
  59. package/dist/bitcoin/providers/types.js +0 -1
  60. package/dist/bitcoin/transactions/commit.d.ts +0 -89
  61. package/dist/bitcoin/transactions/commit.js +0 -311
  62. package/dist/bitcoin/transactions/index.d.ts +0 -7
  63. package/dist/bitcoin/transactions/index.js +0 -8
  64. package/dist/bitcoin/transfer.d.ts +0 -9
  65. package/dist/bitcoin/transfer.js +0 -26
  66. package/dist/bitcoin/utxo-selection.d.ts +0 -78
  67. package/dist/bitcoin/utxo-selection.js +0 -237
  68. package/dist/bitcoin/utxo.d.ts +0 -26
  69. package/dist/bitcoin/utxo.js +0 -78
  70. package/dist/contexts/credentials-v1.json +0 -195
  71. package/dist/contexts/credentials-v2-examples.json +0 -5
  72. package/dist/contexts/credentials-v2.json +0 -301
  73. package/dist/contexts/credentials.json +0 -195
  74. package/dist/contexts/data-integrity-v2.json +0 -81
  75. package/dist/contexts/dids.json +0 -57
  76. package/dist/contexts/ed255192020.json +0 -93
  77. package/dist/contexts/ordinals-plus.json +0 -23
  78. package/dist/contexts/originals.json +0 -22
  79. package/dist/core/OriginalsSDK.d.ts +0 -158
  80. package/dist/core/OriginalsSDK.js +0 -274
  81. package/dist/crypto/Multikey.d.ts +0 -30
  82. package/dist/crypto/Multikey.js +0 -149
  83. package/dist/crypto/Signer.d.ts +0 -21
  84. package/dist/crypto/Signer.js +0 -196
  85. package/dist/crypto/noble-init.d.ts +0 -18
  86. package/dist/crypto/noble-init.js +0 -106
  87. package/dist/did/BtcoDidResolver.d.ts +0 -57
  88. package/dist/did/BtcoDidResolver.js +0 -166
  89. package/dist/did/DIDManager.d.ts +0 -101
  90. package/dist/did/DIDManager.js +0 -493
  91. package/dist/did/Ed25519Verifier.d.ts +0 -30
  92. package/dist/did/Ed25519Verifier.js +0 -59
  93. package/dist/did/KeyManager.d.ts +0 -17
  94. package/dist/did/KeyManager.js +0 -207
  95. package/dist/did/WebVHManager.d.ts +0 -100
  96. package/dist/did/WebVHManager.js +0 -304
  97. package/dist/did/createBtcoDidDocument.d.ts +0 -10
  98. package/dist/did/createBtcoDidDocument.js +0 -42
  99. package/dist/did/providers/OrdinalsClientProviderAdapter.d.ts +0 -23
  100. package/dist/did/providers/OrdinalsClientProviderAdapter.js +0 -51
  101. package/dist/events/EventEmitter.d.ts +0 -115
  102. package/dist/events/EventEmitter.js +0 -198
  103. package/dist/events/index.d.ts +0 -7
  104. package/dist/events/index.js +0 -6
  105. package/dist/events/types.d.ts +0 -286
  106. package/dist/events/types.js +0 -9
  107. package/dist/examples/basic-usage.d.ts +0 -3
  108. package/dist/examples/basic-usage.js +0 -62
  109. package/dist/examples/run.d.ts +0 -1
  110. package/dist/examples/run.js +0 -4
  111. package/dist/index.d.ts +0 -39
  112. package/dist/index.js +0 -47
  113. package/dist/lifecycle/BatchOperations.d.ts +0 -147
  114. package/dist/lifecycle/BatchOperations.js +0 -251
  115. package/dist/lifecycle/LifecycleManager.d.ts +0 -116
  116. package/dist/lifecycle/LifecycleManager.js +0 -971
  117. package/dist/lifecycle/OriginalsAsset.d.ts +0 -164
  118. package/dist/lifecycle/OriginalsAsset.js +0 -380
  119. package/dist/lifecycle/ProvenanceQuery.d.ts +0 -126
  120. package/dist/lifecycle/ProvenanceQuery.js +0 -220
  121. package/dist/lifecycle/ResourceVersioning.d.ts +0 -73
  122. package/dist/lifecycle/ResourceVersioning.js +0 -127
  123. package/dist/migration/MigrationManager.d.ts +0 -86
  124. package/dist/migration/MigrationManager.js +0 -412
  125. package/dist/migration/audit/AuditLogger.d.ts +0 -51
  126. package/dist/migration/audit/AuditLogger.js +0 -156
  127. package/dist/migration/checkpoint/CheckpointManager.d.ts +0 -31
  128. package/dist/migration/checkpoint/CheckpointManager.js +0 -96
  129. package/dist/migration/checkpoint/CheckpointStorage.d.ts +0 -26
  130. package/dist/migration/checkpoint/CheckpointStorage.js +0 -89
  131. package/dist/migration/index.d.ts +0 -22
  132. package/dist/migration/index.js +0 -27
  133. package/dist/migration/operations/BaseMigration.d.ts +0 -48
  134. package/dist/migration/operations/BaseMigration.js +0 -83
  135. package/dist/migration/operations/PeerToBtcoMigration.d.ts +0 -25
  136. package/dist/migration/operations/PeerToBtcoMigration.js +0 -67
  137. package/dist/migration/operations/PeerToWebvhMigration.d.ts +0 -19
  138. package/dist/migration/operations/PeerToWebvhMigration.js +0 -46
  139. package/dist/migration/operations/WebvhToBtcoMigration.d.ts +0 -25
  140. package/dist/migration/operations/WebvhToBtcoMigration.js +0 -67
  141. package/dist/migration/rollback/RollbackManager.d.ts +0 -29
  142. package/dist/migration/rollback/RollbackManager.js +0 -146
  143. package/dist/migration/state/StateMachine.d.ts +0 -25
  144. package/dist/migration/state/StateMachine.js +0 -76
  145. package/dist/migration/state/StateTracker.d.ts +0 -36
  146. package/dist/migration/state/StateTracker.js +0 -123
  147. package/dist/migration/types.d.ts +0 -306
  148. package/dist/migration/types.js +0 -33
  149. package/dist/migration/validation/BitcoinValidator.d.ts +0 -13
  150. package/dist/migration/validation/BitcoinValidator.js +0 -83
  151. package/dist/migration/validation/CredentialValidator.d.ts +0 -13
  152. package/dist/migration/validation/CredentialValidator.js +0 -46
  153. package/dist/migration/validation/DIDCompatibilityValidator.d.ts +0 -16
  154. package/dist/migration/validation/DIDCompatibilityValidator.js +0 -127
  155. package/dist/migration/validation/LifecycleValidator.d.ts +0 -10
  156. package/dist/migration/validation/LifecycleValidator.js +0 -52
  157. package/dist/migration/validation/StorageValidator.d.ts +0 -10
  158. package/dist/migration/validation/StorageValidator.js +0 -65
  159. package/dist/migration/validation/ValidationPipeline.d.ts +0 -29
  160. package/dist/migration/validation/ValidationPipeline.js +0 -180
  161. package/dist/storage/LocalStorageAdapter.d.ts +0 -11
  162. package/dist/storage/LocalStorageAdapter.js +0 -53
  163. package/dist/storage/MemoryStorageAdapter.d.ts +0 -6
  164. package/dist/storage/MemoryStorageAdapter.js +0 -21
  165. package/dist/storage/StorageAdapter.d.ts +0 -16
  166. package/dist/storage/StorageAdapter.js +0 -1
  167. package/dist/storage/index.d.ts +0 -2
  168. package/dist/storage/index.js +0 -2
  169. package/dist/types/bitcoin.d.ts +0 -84
  170. package/dist/types/bitcoin.js +0 -1
  171. package/dist/types/common.d.ts +0 -82
  172. package/dist/types/common.js +0 -1
  173. package/dist/types/credentials.d.ts +0 -75
  174. package/dist/types/credentials.js +0 -1
  175. package/dist/types/did.d.ts +0 -26
  176. package/dist/types/did.js +0 -1
  177. package/dist/types/index.d.ts +0 -5
  178. package/dist/types/index.js +0 -5
  179. package/dist/types/network.d.ts +0 -78
  180. package/dist/types/network.js +0 -145
  181. package/dist/utils/EventLogger.d.ts +0 -71
  182. package/dist/utils/EventLogger.js +0 -232
  183. package/dist/utils/Logger.d.ts +0 -106
  184. package/dist/utils/Logger.js +0 -257
  185. package/dist/utils/MetricsCollector.d.ts +0 -110
  186. package/dist/utils/MetricsCollector.js +0 -264
  187. package/dist/utils/bitcoin-address.d.ts +0 -38
  188. package/dist/utils/bitcoin-address.js +0 -113
  189. package/dist/utils/cbor.d.ts +0 -2
  190. package/dist/utils/cbor.js +0 -9
  191. package/dist/utils/encoding.d.ts +0 -37
  192. package/dist/utils/encoding.js +0 -120
  193. package/dist/utils/hash.d.ts +0 -1
  194. package/dist/utils/hash.js +0 -5
  195. package/dist/utils/retry.d.ts +0 -10
  196. package/dist/utils/retry.js +0 -35
  197. package/dist/utils/satoshi-validation.d.ts +0 -60
  198. package/dist/utils/satoshi-validation.js +0 -156
  199. package/dist/utils/serialization.d.ts +0 -14
  200. package/dist/utils/serialization.js +0 -76
  201. package/dist/utils/telemetry.d.ts +0 -17
  202. package/dist/utils/telemetry.js +0 -24
  203. package/dist/utils/validation.d.ts +0 -5
  204. package/dist/utils/validation.js +0 -98
  205. package/dist/vc/CredentialManager.d.ts +0 -22
  206. package/dist/vc/CredentialManager.js +0 -227
  207. package/dist/vc/Issuer.d.ts +0 -27
  208. package/dist/vc/Issuer.js +0 -70
  209. package/dist/vc/Verifier.d.ts +0 -16
  210. package/dist/vc/Verifier.js +0 -50
  211. package/dist/vc/cryptosuites/bbs.d.ts +0 -44
  212. package/dist/vc/cryptosuites/bbs.js +0 -213
  213. package/dist/vc/cryptosuites/bbsSimple.d.ts +0 -9
  214. package/dist/vc/cryptosuites/bbsSimple.js +0 -12
  215. package/dist/vc/cryptosuites/eddsa.d.ts +0 -30
  216. package/dist/vc/cryptosuites/eddsa.js +0 -81
  217. package/dist/vc/documentLoader.d.ts +0 -16
  218. package/dist/vc/documentLoader.js +0 -59
  219. package/dist/vc/proofs/data-integrity.d.ts +0 -21
  220. package/dist/vc/proofs/data-integrity.js +0 -15
  221. package/dist/vc/utils/jsonld.d.ts +0 -2
  222. package/dist/vc/utils/jsonld.js +0 -15
  223. package/test/logs/did_webvh_QmNTn9Kkp8dQ75WrF9xqJ2kuDp9QhKc3aPiERRMj8XoTBN_example_com.jsonl +0 -1
  224. package/test/logs/did_webvh_QmNu4MNr8Lr5txx5gYNhuhZDchXsZEu3hJXKYuphpWTPDp_example_com_users_etc_passwd.jsonl +0 -1
  225. package/test/logs/did_webvh_QmR9MrGZACzjKETA8SBRNCKG11HxU85c4bVR2qN5eDCfsD_example_com.jsonl +0 -1
  226. package/test/logs/did_webvh_QmUc5suaqRM2P4nrXxZwqYMfqzhdMqjuL7oJaJbEpCQVCd_example_com_users_etc_passwd.jsonl +0 -1
  227. package/test/logs/did_webvh_QmUkiB2RCV2VZ1RTXsCebWN25Eiy9TLvpzDWAJNjhgvB4X_example_com_etc_passwd.jsonl +0 -1
  228. package/test/logs/did_webvh_QmUoRTe8UMwpAQXZSAW7pjAgZK1tq2X3C6Kfxq3UXGcaGy_example_com_secret.jsonl +0 -1
  229. package/test/logs/did_webvh_QmWWot3chx1t6KwTmcE5i2FeDZ5JMkQw3qXycsKDVmJ9Be_example_com_users_alice.jsonl +0 -1
  230. package/test/logs/did_webvh_QmWvVgALL5kjZdpgR7KZay7J8UiiUr834kkRmWeFAxjAuC_example_com_users_etc_passwd.jsonl +0 -1
  231. package/test/logs/did_webvh_QmWwaRQHUZAFcKihFC6xR6tRTTrQhHPTku6azf1egWbpy1_example_com_users_alice.jsonl +0 -1
  232. package/test/logs/did_webvh_QmXJLtkz23r7AozbtXsZMKWnVU6rd38CkVtjdWuATU3Yp6_example_com_users_alice123_profile.jsonl +0 -1
  233. package/test/logs/did_webvh_QmYsce448po14oDE1wXbyaP6wY9HQgHSKLwdezn1k577SF_example_com_my_org_user_name_test_123.jsonl +0 -1
  234. package/test/logs/did_webvh_QmZBeNzzqajxdfwcDUPZ4P8C5YSXyRztrAwmPiKuKUxmAK_example_com.jsonl +0 -1
  235. package/test/logs/did_webvh_QmZhJsqxizwVbRtqCUkmE6XQunSxtxMt3gbTYadVBNAaEq_example_com.jsonl +0 -1
  236. package/test/logs/did_webvh_QmZk7NHU2D57RzzbMq4tWW9gBa9AqtVTWfiRM6RFdwGVj2_example_com.jsonl +0 -1
  237. package/test/logs/did_webvh_QmZshSXp9w8ovH62zGGBS1b5pGGPsuYiu1VQ935sga2hWF_example_com_level1_level2.jsonl +0 -1
  238. package/test/logs/did_webvh_QmbWAmw7HQL7vKJyCsctZihXf1rmT4sGvggKCPKWcUWjw1_example_com.jsonl +0 -1
  239. package/test/logs/did_webvh_QmbdLUMbYs3juR39TLB6hhrFWLcNg45ybUzeBJCS1MhCh1_example_com_C_Windows_System32.jsonl +0 -1
  240. package/test/logs/did_webvh_QmcaQ1Ma4gkSbae85aCm8Mv4rvdT2Sb2RR3JzYwrm5XBq8_example_com_etc_passwd.jsonl +0 -1
  241. package/test/logs/did_webvh_QmcbA7WQhsBqZSoDpKJHjV8Q5o53h8vmgJhQfo6rqTY5ho_example_com.jsonl +0 -1
  242. package/test/logs/did_webvh_Qmdy8uWr2gkUJrXsThynAug3DASTWwb3onEj89LKmMGZYB_example_com.jsonl +0 -1
  243. package/tests/e2e/README.md +0 -97
  244. package/tests/e2e/example.spec.ts +0 -78
@@ -4,7 +4,8 @@ import {
4
4
  BitcoinTransaction,
5
5
  KeyStore,
6
6
  ExternalSigner,
7
- VerifiableCredential
7
+ VerifiableCredential,
8
+ LayerType
8
9
  } from '../types';
9
10
  import { BitcoinManager } from '../bitcoin/BitcoinManager';
10
11
  import { DIDManager } from '../did/DIDManager';
@@ -26,6 +27,97 @@ import {
26
27
  type BatchOperationOptions,
27
28
  type BatchInscriptionOptions,
28
29
  } from './BatchOperations';
30
+ import {
31
+ type OriginalKind,
32
+ type OriginalManifest,
33
+ type CreateTypedOriginalOptions,
34
+ KindRegistry,
35
+ } from '../kinds';
36
+
37
+ /**
38
+ * Cost estimation result for migration operations
39
+ */
40
+ export interface CostEstimate {
41
+ /** Total estimated cost in satoshis */
42
+ totalSats: number;
43
+ /** Breakdown of costs */
44
+ breakdown: {
45
+ /** Network fee in satoshis */
46
+ networkFee: number;
47
+ /** Data cost for inscription (sat/vB * size) */
48
+ dataCost: number;
49
+ /** Dust output value */
50
+ dustValue: number;
51
+ };
52
+ /** Fee rate used for estimation (sat/vB) */
53
+ feeRate: number;
54
+ /** Data size in bytes */
55
+ dataSize: number;
56
+ /** Target layer for the migration */
57
+ targetLayer: LayerType;
58
+ /** Confidence level of estimate */
59
+ confidence: 'low' | 'medium' | 'high';
60
+ }
61
+
62
+ /**
63
+ * Migration validation result
64
+ */
65
+ export interface MigrationValidation {
66
+ /** Whether the migration is valid */
67
+ valid: boolean;
68
+ /** List of validation errors */
69
+ errors: string[];
70
+ /** List of warnings (non-blocking) */
71
+ warnings: string[];
72
+ /** Current layer of the asset */
73
+ currentLayer: LayerType;
74
+ /** Target layer for migration */
75
+ targetLayer: LayerType;
76
+ /** Checks performed */
77
+ checks: {
78
+ layerTransition: boolean;
79
+ resourcesValid: boolean;
80
+ credentialsValid: boolean;
81
+ didDocumentValid: boolean;
82
+ bitcoinReadiness?: boolean;
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Progress callback for long-running operations
88
+ */
89
+ export type ProgressCallback = (progress: LifecycleProgress) => void;
90
+
91
+ /**
92
+ * Progress information for lifecycle operations
93
+ */
94
+ export interface LifecycleProgress {
95
+ /** Current operation phase */
96
+ phase: 'preparing' | 'validating' | 'processing' | 'committing' | 'confirming' | 'complete' | 'failed';
97
+ /** Progress percentage (0-100) */
98
+ percentage: number;
99
+ /** Human-readable message */
100
+ message: string;
101
+ /** Current operation details */
102
+ details?: {
103
+ currentStep?: number;
104
+ totalSteps?: number;
105
+ transactionId?: string;
106
+ confirmations?: number;
107
+ };
108
+ }
109
+
110
+ /**
111
+ * Options for lifecycle operations with progress tracking
112
+ */
113
+ export interface LifecycleOperationOptions {
114
+ /** Fee rate for Bitcoin operations (sat/vB) */
115
+ feeRate?: number;
116
+ /** Progress callback for operation updates */
117
+ onProgress?: ProgressCallback;
118
+ /** Enable atomic rollback on failure (default: true) */
119
+ atomicRollback?: boolean;
120
+ }
29
121
 
30
122
  export class LifecycleManager {
31
123
  private eventEmitter: EventEmitter;
@@ -219,6 +311,239 @@ export class LifecycleManager {
219
311
  }
220
312
  }
221
313
 
314
+ /**
315
+ * Create a typed Original with kind-specific validation
316
+ *
317
+ * This is the recommended way to create Originals with proper typing and validation.
318
+ * Each kind (App, Agent, Module, Dataset, Media, Document) has specific metadata
319
+ * requirements that are validated before creation.
320
+ *
321
+ * @param kind - The kind of Original to create
322
+ * @param manifest - The manifest containing name, version, resources, and kind-specific metadata
323
+ * @param options - Optional creation options (skipValidation, strictMode)
324
+ * @returns The created OriginalsAsset
325
+ * @throws Error if validation fails (unless skipValidation is true)
326
+ *
327
+ * @example
328
+ * ```typescript
329
+ * // Create a Module Original
330
+ * const moduleAsset = await sdk.lifecycle.createTypedOriginal(
331
+ * OriginalKind.Module,
332
+ * {
333
+ * kind: OriginalKind.Module,
334
+ * name: 'my-utility',
335
+ * version: '1.0.0',
336
+ * resources: [{ id: 'index.js', type: 'code', hash: '...', contentType: 'application/javascript' }],
337
+ * metadata: {
338
+ * format: 'esm',
339
+ * main: 'index.js',
340
+ * }
341
+ * }
342
+ * );
343
+ * ```
344
+ */
345
+ async createTypedOriginal<K extends OriginalKind>(
346
+ kind: K,
347
+ manifest: OriginalManifest<K>,
348
+ options?: CreateTypedOriginalOptions
349
+ ): Promise<OriginalsAsset> {
350
+ const stopTimer = this.logger.startTimer('createTypedOriginal');
351
+ this.logger.info('Creating typed Original', { kind, name: manifest.name, version: manifest.version });
352
+
353
+ try {
354
+ // Verify kind matches
355
+ if (manifest.kind !== kind) {
356
+ throw new Error(`Manifest kind "${manifest.kind}" does not match requested kind "${kind}"`);
357
+ }
358
+
359
+ // Validate manifest using KindRegistry
360
+ const registry = KindRegistry.getInstance();
361
+ registry.validateOrThrow(manifest, options);
362
+
363
+ // Log warnings if any
364
+ if (!options?.skipValidation) {
365
+ const validationResult = registry.validate(manifest, options);
366
+ if (validationResult.warnings.length > 0) {
367
+ for (const warning of validationResult.warnings) {
368
+ this.logger.warn(`[${warning.code}] ${warning.message}`, { path: warning.path });
369
+ }
370
+ }
371
+ }
372
+
373
+ // Create the asset using existing createAsset method
374
+ const asset = await this.createAsset(manifest.resources);
375
+
376
+ // Store the manifest metadata on the asset for future reference
377
+ // We attach it as a non-enumerable property to avoid serialization issues
378
+ Object.defineProperty(asset, '_manifest', {
379
+ value: manifest,
380
+ writable: false,
381
+ enumerable: false,
382
+ configurable: false,
383
+ });
384
+
385
+ // Emit typed:created event
386
+ queueMicrotask(() => {
387
+ const event = {
388
+ type: 'asset:created' as const,
389
+ timestamp: new Date().toISOString(),
390
+ asset: {
391
+ id: asset.id,
392
+ layer: asset.currentLayer,
393
+ resourceCount: manifest.resources.length,
394
+ createdAt: asset.getProvenance().createdAt,
395
+ kind: kind,
396
+ name: manifest.name,
397
+ version: manifest.version,
398
+ }
399
+ };
400
+
401
+ // Emit from LifecycleManager
402
+ this.eventEmitter.emit(event);
403
+ });
404
+
405
+ stopTimer();
406
+ this.logger.info('Typed Original created successfully', {
407
+ assetId: asset.id,
408
+ kind,
409
+ name: manifest.name,
410
+ version: manifest.version,
411
+ });
412
+ this.metrics.recordAssetCreated();
413
+
414
+ return asset;
415
+ } catch (error) {
416
+ stopTimer();
417
+ this.logger.error('Typed Original creation failed', error as Error, {
418
+ kind,
419
+ name: manifest.name,
420
+ version: manifest.version,
421
+ });
422
+ this.metrics.recordError('TYPED_ASSET_CREATION_FAILED', 'createTypedOriginal');
423
+ throw error;
424
+ }
425
+ }
426
+
427
+ /**
428
+ * Get the manifest from a typed Original asset
429
+ * Returns undefined if the asset was not created with createTypedOriginal
430
+ *
431
+ * @param asset - The OriginalsAsset to get manifest from
432
+ * @returns The manifest or undefined
433
+ */
434
+ getManifest<K extends OriginalKind>(asset: OriginalsAsset): OriginalManifest<K> | undefined {
435
+ return (asset as any)._manifest as OriginalManifest<K> | undefined;
436
+ }
437
+
438
+ /**
439
+ * Estimate the cost of creating a typed Original
440
+ * Useful for showing users estimated fees before creation
441
+ *
442
+ * @param manifest - The manifest to estimate
443
+ * @param targetLayer - The target layer (did:webvh or did:btco)
444
+ * @param feeRate - Optional fee rate override (sat/vB)
445
+ * @returns Cost estimate including fees
446
+ */
447
+ async estimateTypedOriginalCost<K extends OriginalKind>(
448
+ manifest: OriginalManifest<K>,
449
+ targetLayer: LayerType,
450
+ feeRate?: number
451
+ ): Promise<CostEstimate> {
452
+ // For webvh, costs are minimal
453
+ if (targetLayer === 'did:webvh') {
454
+ return {
455
+ totalSats: 0,
456
+ breakdown: {
457
+ networkFee: 0,
458
+ dataCost: 0,
459
+ dustValue: 0
460
+ },
461
+ feeRate: 0,
462
+ dataSize: 0,
463
+ targetLayer,
464
+ confidence: 'high'
465
+ };
466
+ }
467
+
468
+ // Calculate total data size including manifest metadata
469
+ let dataSize = 0;
470
+ for (const resource of manifest.resources) {
471
+ if (resource.size) {
472
+ dataSize += resource.size;
473
+ } else if (resource.content) {
474
+ dataSize += Buffer.from(resource.content).length;
475
+ } else {
476
+ // Estimate based on hash length (assume average resource size)
477
+ dataSize += 1000;
478
+ }
479
+ }
480
+
481
+ // Add inscription manifest overhead
482
+ const inscriptionManifest = {
483
+ assetId: `did:peer:placeholder`,
484
+ kind: manifest.kind,
485
+ name: manifest.name,
486
+ version: manifest.version,
487
+ resources: manifest.resources.map(r => ({
488
+ id: r.id,
489
+ hash: r.hash,
490
+ contentType: r.contentType,
491
+ })),
492
+ metadata: manifest.metadata,
493
+ timestamp: new Date().toISOString()
494
+ };
495
+ dataSize += Buffer.from(JSON.stringify(inscriptionManifest)).length;
496
+
497
+ // Get fee rate from oracle or use provided/default
498
+ let effectiveFeeRate = feeRate;
499
+ let confidence: 'low' | 'medium' | 'high' = 'medium';
500
+
501
+ if (!effectiveFeeRate) {
502
+ if (this.config.feeOracle) {
503
+ try {
504
+ effectiveFeeRate = await this.config.feeOracle.estimateFeeRate(1);
505
+ confidence = 'high';
506
+ } catch {
507
+ // Fallback to default
508
+ }
509
+ }
510
+
511
+ if (!effectiveFeeRate && this.config.ordinalsProvider) {
512
+ try {
513
+ effectiveFeeRate = await this.config.ordinalsProvider.estimateFee(1);
514
+ confidence = 'medium';
515
+ } catch {
516
+ // Fallback to default
517
+ }
518
+ }
519
+
520
+ if (!effectiveFeeRate) {
521
+ effectiveFeeRate = 10;
522
+ confidence = 'low';
523
+ }
524
+ }
525
+
526
+ // Transaction overhead (commit + reveal structure)
527
+ const txOverhead = 200 + 122; // Base tx + inscription overhead
528
+ const totalVbytes = txOverhead + Math.ceil(dataSize / 4); // Witness data is ~1/4 weight
529
+
530
+ const networkFee = totalVbytes * effectiveFeeRate;
531
+ const dustValue = 330; // Minimum output value
532
+
533
+ return {
534
+ totalSats: networkFee + dustValue,
535
+ breakdown: {
536
+ networkFee,
537
+ dataCost: Math.ceil(dataSize / 4) * effectiveFeeRate,
538
+ dustValue
539
+ },
540
+ feeRate: effectiveFeeRate,
541
+ dataSize,
542
+ targetLayer,
543
+ confidence
544
+ };
545
+ }
546
+
222
547
  async publishToWeb(
223
548
  asset: OriginalsAsset,
224
549
  publisherDidOrSigner: string | ExternalSigner
@@ -1213,6 +1538,589 @@ export class LifecycleManager {
1213
1538
  savingsPercentage
1214
1539
  };
1215
1540
  }
1541
+
1542
+ // ===== Clean Lifecycle API =====
1543
+ // These methods provide a cleaner, more intuitive API while maintaining
1544
+ // backward compatibility with the existing methods.
1545
+
1546
+ /**
1547
+ * Create a draft asset (did:peer layer)
1548
+ *
1549
+ * This is the entry point for creating new Originals. Draft assets are
1550
+ * stored locally and can be published or inscribed later.
1551
+ *
1552
+ * @param resources - Array of resources to include in the asset
1553
+ * @param options - Optional configuration including progress callback
1554
+ * @returns The newly created OriginalsAsset in did:peer layer
1555
+ *
1556
+ * @example
1557
+ * ```typescript
1558
+ * const draft = await sdk.lifecycle.createDraft([
1559
+ * { id: 'main', type: 'code', contentType: 'text/javascript', hash: '...' }
1560
+ * ], {
1561
+ * onProgress: (p) => console.log(p.message)
1562
+ * });
1563
+ * ```
1564
+ */
1565
+ async createDraft(
1566
+ resources: AssetResource[],
1567
+ options?: LifecycleOperationOptions
1568
+ ): Promise<OriginalsAsset> {
1569
+ const onProgress = options?.onProgress;
1570
+
1571
+ onProgress?.({
1572
+ phase: 'preparing',
1573
+ percentage: 0,
1574
+ message: 'Preparing draft asset...'
1575
+ });
1576
+
1577
+ onProgress?.({
1578
+ phase: 'validating',
1579
+ percentage: 20,
1580
+ message: 'Validating resources...'
1581
+ });
1582
+
1583
+ try {
1584
+ onProgress?.({
1585
+ phase: 'processing',
1586
+ percentage: 50,
1587
+ message: 'Creating DID document...'
1588
+ });
1589
+
1590
+ const asset = await this.createAsset(resources);
1591
+
1592
+ onProgress?.({
1593
+ phase: 'complete',
1594
+ percentage: 100,
1595
+ message: 'Draft asset created successfully'
1596
+ });
1597
+
1598
+ return asset;
1599
+ } catch (error) {
1600
+ onProgress?.({
1601
+ phase: 'failed',
1602
+ percentage: 0,
1603
+ message: `Failed to create draft: ${error instanceof Error ? error.message : String(error)}`
1604
+ });
1605
+ throw error;
1606
+ }
1607
+ }
1608
+
1609
+ /**
1610
+ * Publish an asset to the web (did:webvh layer)
1611
+ *
1612
+ * Migrates a draft asset from did:peer to did:webvh, making it publicly
1613
+ * discoverable via HTTPS.
1614
+ *
1615
+ * @param asset - The asset to publish (must be in did:peer layer)
1616
+ * @param publisherDidOrSigner - Publisher's DID or external signer
1617
+ * @param options - Optional configuration including progress callback
1618
+ * @returns The published OriginalsAsset in did:webvh layer
1619
+ *
1620
+ * @example
1621
+ * ```typescript
1622
+ * const published = await sdk.lifecycle.publish(draft, 'did:webvh:example.com:user');
1623
+ * ```
1624
+ */
1625
+ async publish(
1626
+ asset: OriginalsAsset,
1627
+ publisherDidOrSigner: string | ExternalSigner,
1628
+ options?: LifecycleOperationOptions
1629
+ ): Promise<OriginalsAsset> {
1630
+ const onProgress = options?.onProgress;
1631
+
1632
+ onProgress?.({
1633
+ phase: 'preparing',
1634
+ percentage: 0,
1635
+ message: 'Preparing to publish...'
1636
+ });
1637
+
1638
+ onProgress?.({
1639
+ phase: 'validating',
1640
+ percentage: 10,
1641
+ message: 'Validating migration...'
1642
+ });
1643
+
1644
+ // Pre-flight validation
1645
+ const validation = await this.validateMigration(asset, 'did:webvh');
1646
+ if (!validation.valid) {
1647
+ onProgress?.({
1648
+ phase: 'failed',
1649
+ percentage: 0,
1650
+ message: `Validation failed: ${validation.errors.join(', ')}`
1651
+ });
1652
+ throw new Error(`Migration validation failed: ${validation.errors.join(', ')}`);
1653
+ }
1654
+
1655
+ try {
1656
+ onProgress?.({
1657
+ phase: 'processing',
1658
+ percentage: 30,
1659
+ message: 'Publishing resources...'
1660
+ });
1661
+
1662
+ onProgress?.({
1663
+ phase: 'committing',
1664
+ percentage: 70,
1665
+ message: 'Finalizing publication...'
1666
+ });
1667
+
1668
+ const published = await this.publishToWeb(asset, publisherDidOrSigner);
1669
+
1670
+ onProgress?.({
1671
+ phase: 'complete',
1672
+ percentage: 100,
1673
+ message: 'Asset published successfully'
1674
+ });
1675
+
1676
+ return published;
1677
+ } catch (error) {
1678
+ onProgress?.({
1679
+ phase: 'failed',
1680
+ percentage: 0,
1681
+ message: `Failed to publish: ${error instanceof Error ? error.message : String(error)}`
1682
+ });
1683
+ throw error;
1684
+ }
1685
+ }
1686
+
1687
+ /**
1688
+ * Inscribe an asset on Bitcoin (did:btco layer)
1689
+ *
1690
+ * Permanently anchors an asset on the Bitcoin blockchain via Ordinals inscription.
1691
+ * This is an irreversible operation.
1692
+ *
1693
+ * @param asset - The asset to inscribe (must be in did:peer or did:webvh layer)
1694
+ * @param options - Optional configuration including fee rate and progress callback
1695
+ * @returns The inscribed OriginalsAsset in did:btco layer
1696
+ *
1697
+ * @example
1698
+ * ```typescript
1699
+ * const inscribed = await sdk.lifecycle.inscribe(published, {
1700
+ * feeRate: 15,
1701
+ * onProgress: (p) => console.log(`${p.percentage}%: ${p.message}`)
1702
+ * });
1703
+ * ```
1704
+ */
1705
+ async inscribe(
1706
+ asset: OriginalsAsset,
1707
+ options?: LifecycleOperationOptions
1708
+ ): Promise<OriginalsAsset> {
1709
+ const onProgress = options?.onProgress;
1710
+ const feeRate = options?.feeRate;
1711
+
1712
+ onProgress?.({
1713
+ phase: 'preparing',
1714
+ percentage: 0,
1715
+ message: 'Preparing inscription...'
1716
+ });
1717
+
1718
+ onProgress?.({
1719
+ phase: 'validating',
1720
+ percentage: 10,
1721
+ message: 'Validating migration...'
1722
+ });
1723
+
1724
+ // Pre-flight validation
1725
+ const validation = await this.validateMigration(asset, 'did:btco');
1726
+ if (!validation.valid) {
1727
+ onProgress?.({
1728
+ phase: 'failed',
1729
+ percentage: 0,
1730
+ message: `Validation failed: ${validation.errors.join(', ')}`
1731
+ });
1732
+ throw new Error(`Migration validation failed: ${validation.errors.join(', ')}`);
1733
+ }
1734
+
1735
+ // Show cost estimate
1736
+ if (onProgress) {
1737
+ const estimate = await this.estimateCost(asset, 'did:btco', feeRate);
1738
+ onProgress({
1739
+ phase: 'preparing',
1740
+ percentage: 20,
1741
+ message: `Estimated cost: ${estimate.totalSats} sats (${estimate.feeRate} sat/vB)`
1742
+ });
1743
+ }
1744
+
1745
+ try {
1746
+ onProgress?.({
1747
+ phase: 'processing',
1748
+ percentage: 30,
1749
+ message: 'Creating commit transaction...',
1750
+ details: { currentStep: 1, totalSteps: 3 }
1751
+ });
1752
+
1753
+ onProgress?.({
1754
+ phase: 'committing',
1755
+ percentage: 60,
1756
+ message: 'Broadcasting reveal transaction...',
1757
+ details: { currentStep: 2, totalSteps: 3 }
1758
+ });
1759
+
1760
+ const inscribed = await this.inscribeOnBitcoin(asset, feeRate);
1761
+
1762
+ onProgress?.({
1763
+ phase: 'confirming',
1764
+ percentage: 90,
1765
+ message: 'Waiting for confirmation...',
1766
+ details: { currentStep: 3, totalSteps: 3 }
1767
+ });
1768
+
1769
+ onProgress?.({
1770
+ phase: 'complete',
1771
+ percentage: 100,
1772
+ message: 'Asset inscribed successfully'
1773
+ });
1774
+
1775
+ return inscribed;
1776
+ } catch (error) {
1777
+ onProgress?.({
1778
+ phase: 'failed',
1779
+ percentage: 0,
1780
+ message: `Failed to inscribe: ${error instanceof Error ? error.message : String(error)}`
1781
+ });
1782
+ throw error;
1783
+ }
1784
+ }
1785
+
1786
+ /**
1787
+ * Transfer ownership of a Bitcoin-inscribed asset
1788
+ *
1789
+ * Transfers an inscribed asset to a new owner. Only works for assets
1790
+ * in the did:btco layer.
1791
+ *
1792
+ * @param asset - The asset to transfer (must be in did:btco layer)
1793
+ * @param newOwnerAddress - Bitcoin address of the new owner
1794
+ * @param options - Optional configuration including progress callback
1795
+ * @returns The Bitcoin transaction for the transfer
1796
+ *
1797
+ * @example
1798
+ * ```typescript
1799
+ * const tx = await sdk.lifecycle.transfer(inscribed, 'bc1q...newowner');
1800
+ * console.log('Transfer txid:', tx.txid);
1801
+ * ```
1802
+ */
1803
+ async transfer(
1804
+ asset: OriginalsAsset,
1805
+ newOwnerAddress: string,
1806
+ options?: LifecycleOperationOptions
1807
+ ): Promise<BitcoinTransaction> {
1808
+ const onProgress = options?.onProgress;
1809
+
1810
+ onProgress?.({
1811
+ phase: 'preparing',
1812
+ percentage: 0,
1813
+ message: 'Preparing transfer...'
1814
+ });
1815
+
1816
+ onProgress?.({
1817
+ phase: 'validating',
1818
+ percentage: 10,
1819
+ message: 'Validating transfer...'
1820
+ });
1821
+
1822
+ // Validate asset is in correct layer
1823
+ if (asset.currentLayer !== 'did:btco') {
1824
+ onProgress?.({
1825
+ phase: 'failed',
1826
+ percentage: 0,
1827
+ message: 'Asset must be inscribed on Bitcoin before transfer'
1828
+ });
1829
+ throw new Error('Asset must be inscribed on Bitcoin before transfer');
1830
+ }
1831
+
1832
+ try {
1833
+ onProgress?.({
1834
+ phase: 'processing',
1835
+ percentage: 30,
1836
+ message: 'Creating transfer transaction...'
1837
+ });
1838
+
1839
+ onProgress?.({
1840
+ phase: 'committing',
1841
+ percentage: 60,
1842
+ message: 'Broadcasting transaction...'
1843
+ });
1844
+
1845
+ const tx = await this.transferOwnership(asset, newOwnerAddress);
1846
+
1847
+ onProgress?.({
1848
+ phase: 'confirming',
1849
+ percentage: 90,
1850
+ message: 'Waiting for confirmation...',
1851
+ details: { transactionId: tx.txid }
1852
+ });
1853
+
1854
+ onProgress?.({
1855
+ phase: 'complete',
1856
+ percentage: 100,
1857
+ message: 'Transfer complete',
1858
+ details: { transactionId: tx.txid }
1859
+ });
1860
+
1861
+ return tx;
1862
+ } catch (error) {
1863
+ onProgress?.({
1864
+ phase: 'failed',
1865
+ percentage: 0,
1866
+ message: `Failed to transfer: ${error instanceof Error ? error.message : String(error)}`
1867
+ });
1868
+ throw error;
1869
+ }
1870
+ }
1871
+
1872
+ // ===== Cost Estimation =====
1873
+
1874
+ /**
1875
+ * Estimate the cost of migrating an asset to a target layer
1876
+ *
1877
+ * Returns a detailed breakdown of expected costs for Bitcoin operations.
1878
+ * For did:webvh migrations, costs are minimal (only hosting).
1879
+ *
1880
+ * @param asset - The asset to estimate costs for
1881
+ * @param targetLayer - The target layer for migration
1882
+ * @param feeRate - Optional fee rate override (sat/vB)
1883
+ * @returns Detailed cost estimate
1884
+ *
1885
+ * @example
1886
+ * ```typescript
1887
+ * const cost = await sdk.lifecycle.estimateCost(draft, 'did:btco', 10);
1888
+ * console.log(`Estimated cost: ${cost.totalSats} sats`);
1889
+ * ```
1890
+ */
1891
+ async estimateCost(
1892
+ asset: OriginalsAsset,
1893
+ targetLayer: LayerType,
1894
+ feeRate?: number
1895
+ ): Promise<CostEstimate> {
1896
+ // For webvh, costs are minimal (just hosting costs not applicable here)
1897
+ if (targetLayer === 'did:webvh') {
1898
+ return {
1899
+ totalSats: 0,
1900
+ breakdown: {
1901
+ networkFee: 0,
1902
+ dataCost: 0,
1903
+ dustValue: 0
1904
+ },
1905
+ feeRate: 0,
1906
+ dataSize: 0,
1907
+ targetLayer,
1908
+ confidence: 'high'
1909
+ };
1910
+ }
1911
+
1912
+ // For btco, calculate inscription costs
1913
+ if (targetLayer === 'did:btco') {
1914
+ // Calculate manifest size
1915
+ const manifest = {
1916
+ assetId: asset.id,
1917
+ resources: asset.resources.map(res => ({
1918
+ id: res.id,
1919
+ hash: res.hash,
1920
+ contentType: res.contentType,
1921
+ url: res.url
1922
+ })),
1923
+ timestamp: new Date().toISOString()
1924
+ };
1925
+ const dataSize = Buffer.from(JSON.stringify(manifest)).length;
1926
+
1927
+ // Get fee rate from oracle or use provided/default
1928
+ let effectiveFeeRate = feeRate;
1929
+ let confidence: 'low' | 'medium' | 'high' = 'medium';
1930
+
1931
+ if (!effectiveFeeRate) {
1932
+ // Try to get from fee oracle
1933
+ if (this.config.feeOracle) {
1934
+ try {
1935
+ effectiveFeeRate = await this.config.feeOracle.estimateFeeRate(1);
1936
+ confidence = 'high';
1937
+ } catch {
1938
+ // Fallback to default
1939
+ }
1940
+ }
1941
+
1942
+ // Try ordinals provider
1943
+ if (!effectiveFeeRate && this.config.ordinalsProvider) {
1944
+ try {
1945
+ effectiveFeeRate = await this.config.ordinalsProvider.estimateFee(1);
1946
+ confidence = 'medium';
1947
+ } catch {
1948
+ // Fallback to default
1949
+ }
1950
+ }
1951
+
1952
+ // Use default if no oracle available
1953
+ if (!effectiveFeeRate) {
1954
+ effectiveFeeRate = 10; // Conservative default
1955
+ confidence = 'low';
1956
+ }
1957
+ }
1958
+
1959
+ // Transaction structure estimation:
1960
+ // - Commit transaction: ~200 vB base + input overhead
1961
+ // - Reveal transaction: ~200 vB base + inscription envelope + data
1962
+ // Inscription envelope overhead: ~122 bytes
1963
+ const commitTxSize = 200;
1964
+ const revealTxSize = 200 + 122 + dataSize;
1965
+ const totalSize = commitTxSize + revealTxSize;
1966
+
1967
+ const networkFee = totalSize * effectiveFeeRate;
1968
+ const dustValue = 546; // Standard dust limit for P2TR
1969
+ const totalSats = networkFee + dustValue;
1970
+
1971
+ return {
1972
+ totalSats,
1973
+ breakdown: {
1974
+ networkFee,
1975
+ dataCost: dataSize * effectiveFeeRate,
1976
+ dustValue
1977
+ },
1978
+ feeRate: effectiveFeeRate,
1979
+ dataSize,
1980
+ targetLayer,
1981
+ confidence
1982
+ };
1983
+ }
1984
+
1985
+ // For peer layer (no migration needed)
1986
+ return {
1987
+ totalSats: 0,
1988
+ breakdown: {
1989
+ networkFee: 0,
1990
+ dataCost: 0,
1991
+ dustValue: 0
1992
+ },
1993
+ feeRate: 0,
1994
+ dataSize: 0,
1995
+ targetLayer,
1996
+ confidence: 'high'
1997
+ };
1998
+ }
1999
+
2000
+ // ===== Migration Validation =====
2001
+
2002
+ /**
2003
+ * Validate whether an asset can be migrated to a target layer
2004
+ *
2005
+ * Performs comprehensive pre-flight checks including:
2006
+ * - Valid layer transition
2007
+ * - Resource integrity
2008
+ * - Credential validity
2009
+ * - DID document structure
2010
+ * - Bitcoin readiness (for did:btco)
2011
+ *
2012
+ * @param asset - The asset to validate
2013
+ * @param targetLayer - The target layer for migration
2014
+ * @returns Detailed validation result
2015
+ *
2016
+ * @example
2017
+ * ```typescript
2018
+ * const validation = await sdk.lifecycle.validateMigration(draft, 'did:webvh');
2019
+ * if (!validation.valid) {
2020
+ * console.error('Cannot migrate:', validation.errors);
2021
+ * }
2022
+ * ```
2023
+ */
2024
+ async validateMigration(
2025
+ asset: OriginalsAsset,
2026
+ targetLayer: LayerType
2027
+ ): Promise<MigrationValidation> {
2028
+ const errors: string[] = [];
2029
+ const warnings: string[] = [];
2030
+ const checks = {
2031
+ layerTransition: false,
2032
+ resourcesValid: false,
2033
+ credentialsValid: false,
2034
+ didDocumentValid: false,
2035
+ bitcoinReadiness: undefined as boolean | undefined
2036
+ };
2037
+
2038
+ // Check layer transition validity
2039
+ const validTransitions: Record<LayerType, LayerType[]> = {
2040
+ 'did:peer': ['did:webvh', 'did:btco'],
2041
+ 'did:webvh': ['did:btco'],
2042
+ 'did:btco': []
2043
+ };
2044
+
2045
+ if (validTransitions[asset.currentLayer].includes(targetLayer)) {
2046
+ checks.layerTransition = true;
2047
+ } else {
2048
+ errors.push(`Invalid migration from ${asset.currentLayer} to ${targetLayer}`);
2049
+ }
2050
+
2051
+ // Validate resources
2052
+ if (asset.resources.length === 0) {
2053
+ errors.push('Asset must have at least one resource');
2054
+ } else {
2055
+ let resourcesValid = true;
2056
+ for (const resource of asset.resources) {
2057
+ if (!resource.id || !resource.type || !resource.contentType || !resource.hash) {
2058
+ resourcesValid = false;
2059
+ errors.push(`Resource ${resource.id || 'unknown'} is missing required fields`);
2060
+ }
2061
+ if (resource.hash && !/^[0-9a-fA-F]+$/.test(resource.hash)) {
2062
+ resourcesValid = false;
2063
+ errors.push(`Resource ${resource.id} has invalid hash format`);
2064
+ }
2065
+ }
2066
+ checks.resourcesValid = resourcesValid;
2067
+ }
2068
+
2069
+ // Validate DID document
2070
+ if (asset.did && asset.did.id) {
2071
+ checks.didDocumentValid = true;
2072
+ } else {
2073
+ errors.push('Asset has invalid or missing DID document');
2074
+ }
2075
+
2076
+ // Validate credentials (structural check)
2077
+ if (asset.credentials.length > 0) {
2078
+ let credentialsValid = true;
2079
+ for (const cred of asset.credentials) {
2080
+ if (!cred.type || !cred.issuer || !cred.issuanceDate) {
2081
+ credentialsValid = false;
2082
+ warnings.push('Asset has credentials with missing fields');
2083
+ }
2084
+ }
2085
+ checks.credentialsValid = credentialsValid;
2086
+ } else {
2087
+ checks.credentialsValid = true; // No credentials is valid
2088
+ }
2089
+
2090
+ // Bitcoin-specific checks
2091
+ if (targetLayer === 'did:btco') {
2092
+ checks.bitcoinReadiness = true;
2093
+
2094
+ // Check if ordinals provider is configured
2095
+ if (!this.config.ordinalsProvider) {
2096
+ checks.bitcoinReadiness = false;
2097
+ errors.push('Bitcoin inscription requires an ordinalsProvider to be configured');
2098
+ }
2099
+
2100
+ // Warn about large data sizes
2101
+ const manifestSize = JSON.stringify({
2102
+ assetId: asset.id,
2103
+ resources: asset.resources.map(r => ({
2104
+ id: r.id,
2105
+ hash: r.hash,
2106
+ contentType: r.contentType
2107
+ }))
2108
+ }).length;
2109
+
2110
+ if (manifestSize > 100000) {
2111
+ warnings.push(`Large manifest size (${manifestSize} bytes) may result in high inscription costs`);
2112
+ }
2113
+ }
2114
+
2115
+ return {
2116
+ valid: errors.length === 0,
2117
+ errors,
2118
+ warnings,
2119
+ currentLayer: asset.currentLayer,
2120
+ targetLayer,
2121
+ checks
2122
+ };
2123
+ }
1216
2124
  }
1217
2125
 
1218
2126