@originals/sdk 1.8.0 → 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,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebVHCelManager - CEL Manager for did:webvh Layer
|
|
3
|
+
*
|
|
4
|
+
* Manages migration of Originals assets to the did:webvh layer (Layer 1).
|
|
5
|
+
* This layer provides HTTP-based witnessing for verifiable history.
|
|
6
|
+
*
|
|
7
|
+
* The did:webvh (Web Verifiable History) method combines domain-based
|
|
8
|
+
* resolution with cryptographic event logging for discoverable assets.
|
|
9
|
+
*
|
|
10
|
+
* @see https://identity.foundation/didwebvh/
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { EventLog, ExternalReference, DataIntegrityProof, UpdateOptions, AssetState } from '../types';
|
|
14
|
+
import { updateEventLog } from '../algorithms/updateEventLog';
|
|
15
|
+
import { witnessEvent } from '../algorithms/witnessEvent';
|
|
16
|
+
import type { WitnessService } from '../witnesses/WitnessService';
|
|
17
|
+
import type { CelSigner } from './PeerCelManager';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Configuration options for WebVHCelManager
|
|
21
|
+
*/
|
|
22
|
+
export interface WebVHCelConfig {
|
|
23
|
+
/** The DID URL of the verification method for signing */
|
|
24
|
+
verificationMethod?: string;
|
|
25
|
+
/** The purpose of proofs (defaults to 'assertionMethod') */
|
|
26
|
+
proofPurpose?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Migration data stored in the update event when migrating to webvh
|
|
31
|
+
*/
|
|
32
|
+
export interface WebVHMigrationData {
|
|
33
|
+
/** The source DID from the previous layer */
|
|
34
|
+
sourceDid: string;
|
|
35
|
+
/** The new did:webvh DID */
|
|
36
|
+
targetDid: string;
|
|
37
|
+
/** The target layer */
|
|
38
|
+
layer: 'webvh';
|
|
39
|
+
/** The domain hosting the did:webvh */
|
|
40
|
+
domain: string;
|
|
41
|
+
/** ISO 8601 timestamp of migration */
|
|
42
|
+
migratedAt: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* WebVHCelManager - Manages CEL-based asset migration to did:webvh layer
|
|
47
|
+
*
|
|
48
|
+
* The webvh layer is the first publication layer for Originals assets.
|
|
49
|
+
* Assets at this layer:
|
|
50
|
+
* - Have a did:webvh identifier based on a domain
|
|
51
|
+
* - Can have HTTP-based witness attestations
|
|
52
|
+
* - Are discoverable via web-based DID resolution
|
|
53
|
+
* - Can be further migrated to did:btco layer
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const httpWitness = new HttpWitness('https://witness.example.com/api/attest');
|
|
58
|
+
* const manager = new WebVHCelManager(
|
|
59
|
+
* async (data) => createEdDsaProof(data, privateKey),
|
|
60
|
+
* 'example.com',
|
|
61
|
+
* [httpWitness]
|
|
62
|
+
* );
|
|
63
|
+
*
|
|
64
|
+
* const webvhLog = await manager.migrate(peerLog);
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export class WebVHCelManager {
|
|
68
|
+
private signer: CelSigner;
|
|
69
|
+
private domain: string;
|
|
70
|
+
private witnesses: WitnessService[];
|
|
71
|
+
private config: WebVHCelConfig;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Creates a new WebVHCelManager instance
|
|
75
|
+
*
|
|
76
|
+
* @param signer - Function that signs data and returns a DataIntegrityProof
|
|
77
|
+
* @param domain - The domain for the did:webvh DID (e.g., 'example.com')
|
|
78
|
+
* @param witnesses - Optional array of witness services for attestations
|
|
79
|
+
* @param config - Optional configuration options
|
|
80
|
+
*/
|
|
81
|
+
constructor(
|
|
82
|
+
signer: CelSigner,
|
|
83
|
+
domain: string,
|
|
84
|
+
witnesses: WitnessService[] = [],
|
|
85
|
+
config: WebVHCelConfig = {}
|
|
86
|
+
) {
|
|
87
|
+
if (typeof signer !== 'function') {
|
|
88
|
+
throw new Error('WebVHCelManager requires a signer function');
|
|
89
|
+
}
|
|
90
|
+
if (!domain || typeof domain !== 'string') {
|
|
91
|
+
throw new Error('WebVHCelManager requires a valid domain string');
|
|
92
|
+
}
|
|
93
|
+
// Basic domain validation
|
|
94
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$/.test(domain) && !/^[a-zA-Z0-9]$/.test(domain)) {
|
|
95
|
+
throw new Error(`Invalid domain format: ${domain}`);
|
|
96
|
+
}
|
|
97
|
+
if (!Array.isArray(witnesses)) {
|
|
98
|
+
throw new Error('witnesses must be an array');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.signer = signer;
|
|
102
|
+
this.domain = domain;
|
|
103
|
+
this.witnesses = witnesses;
|
|
104
|
+
this.config = {
|
|
105
|
+
proofPurpose: 'assertionMethod',
|
|
106
|
+
...config,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Migrates a peer layer event log to the did:webvh layer
|
|
112
|
+
*
|
|
113
|
+
* This method:
|
|
114
|
+
* 1. Validates the input log (must have a create event with peer layer data)
|
|
115
|
+
* 2. Generates a new did:webvh DID based on the domain
|
|
116
|
+
* 3. Creates an update event with migration data
|
|
117
|
+
* 4. Optionally adds witness proofs from configured witnesses
|
|
118
|
+
* 5. Returns the updated EventLog
|
|
119
|
+
*
|
|
120
|
+
* @param peerLog - The event log from the peer layer to migrate
|
|
121
|
+
* @returns Promise resolving to an EventLog with the migration event appended
|
|
122
|
+
*
|
|
123
|
+
* @throws Error if the log is empty, deactivated, or not from peer layer
|
|
124
|
+
* @throws Error if signer produces invalid proof
|
|
125
|
+
* @throws Error if witness service fails (if witnesses configured)
|
|
126
|
+
*/
|
|
127
|
+
async migrate(peerLog: EventLog): Promise<EventLog> {
|
|
128
|
+
// Validate input log
|
|
129
|
+
if (!peerLog || !peerLog.events || peerLog.events.length === 0) {
|
|
130
|
+
throw new Error('Cannot migrate an empty event log');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Get the create event to extract source DID
|
|
134
|
+
const createEvent = peerLog.events[0];
|
|
135
|
+
if (createEvent.type !== 'create') {
|
|
136
|
+
throw new Error('First event must be a create event');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Extract source data
|
|
140
|
+
const createData = createEvent.data as Record<string, unknown>;
|
|
141
|
+
const sourceDid = createData.did as string;
|
|
142
|
+
|
|
143
|
+
if (!sourceDid) {
|
|
144
|
+
throw new Error('Create event must have a did field');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Validate source is from peer layer
|
|
148
|
+
const sourceLayer = createData.layer as string;
|
|
149
|
+
if (sourceLayer && sourceLayer !== 'peer') {
|
|
150
|
+
throw new Error(`Cannot migrate from ${sourceLayer} layer to webvh layer. Expected peer layer.`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check if log is already deactivated
|
|
154
|
+
const lastEvent = peerLog.events[peerLog.events.length - 1];
|
|
155
|
+
if (lastEvent.type === 'deactivate') {
|
|
156
|
+
throw new Error('Cannot migrate a deactivated event log');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Generate did:webvh DID
|
|
160
|
+
const targetDid = this.generateWebVHDid(sourceDid);
|
|
161
|
+
|
|
162
|
+
// Prepare migration data
|
|
163
|
+
const migrationData: WebVHMigrationData = {
|
|
164
|
+
sourceDid,
|
|
165
|
+
targetDid,
|
|
166
|
+
layer: 'webvh',
|
|
167
|
+
domain: this.domain,
|
|
168
|
+
migratedAt: new Date().toISOString(),
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Build update options
|
|
172
|
+
const updateOptions: UpdateOptions = {
|
|
173
|
+
signer: this.signer,
|
|
174
|
+
verificationMethod: this.config.verificationMethod || `${targetDid}#key-0`,
|
|
175
|
+
proofPurpose: this.config.proofPurpose,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Create the update event with migration data
|
|
179
|
+
let updatedLog = await updateEventLog(peerLog, migrationData, updateOptions);
|
|
180
|
+
|
|
181
|
+
// Add witness proofs if witnesses are configured
|
|
182
|
+
if (this.witnesses.length > 0) {
|
|
183
|
+
// Get the last event (the migration event we just added)
|
|
184
|
+
const lastEventIndex = updatedLog.events.length - 1;
|
|
185
|
+
let witnessedEvent = updatedLog.events[lastEventIndex];
|
|
186
|
+
|
|
187
|
+
// Add witness proofs from each configured witness
|
|
188
|
+
for (const witness of this.witnesses) {
|
|
189
|
+
witnessedEvent = await witnessEvent(witnessedEvent, witness);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Replace the last event with the witnessed version
|
|
193
|
+
updatedLog = {
|
|
194
|
+
...updatedLog,
|
|
195
|
+
events: [
|
|
196
|
+
...updatedLog.events.slice(0, lastEventIndex),
|
|
197
|
+
witnessedEvent,
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return updatedLog;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Generates a did:webvh DID for this domain
|
|
207
|
+
*
|
|
208
|
+
* The did:webvh format is: did:webvh:{domain}:{id}
|
|
209
|
+
* where {id} is derived from the source DID to maintain linkage.
|
|
210
|
+
*
|
|
211
|
+
* @param sourceDid - The source DID to derive the webvh DID from
|
|
212
|
+
* @returns A did:webvh string
|
|
213
|
+
*/
|
|
214
|
+
private generateWebVHDid(sourceDid: string): string {
|
|
215
|
+
// Extract a stable identifier from the source DID
|
|
216
|
+
// For did:peer, extract the key portion after the method
|
|
217
|
+
let idPart: string;
|
|
218
|
+
|
|
219
|
+
if (sourceDid.startsWith('did:peer:')) {
|
|
220
|
+
// For peer DIDs, use a hash-derived portion
|
|
221
|
+
// did:peer:4zQm... -> use the multibase portion
|
|
222
|
+
const peerPart = sourceDid.replace('did:peer:', '');
|
|
223
|
+
// Take first 32 chars of the peer DID identifier for brevity
|
|
224
|
+
idPart = peerPart.substring(0, Math.min(32, peerPart.length));
|
|
225
|
+
} else if (sourceDid.startsWith('did:key:')) {
|
|
226
|
+
// For key DIDs, extract the key portion
|
|
227
|
+
idPart = sourceDid.replace('did:key:', '').substring(0, 32);
|
|
228
|
+
} else {
|
|
229
|
+
// For other DIDs, create a hash-based identifier
|
|
230
|
+
idPart = this.hashIdentifier(sourceDid);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Sanitize for URL safety (replace invalid chars)
|
|
234
|
+
idPart = idPart.replace(/[^a-zA-Z0-9]/g, '');
|
|
235
|
+
|
|
236
|
+
return `did:webvh:${this.domain}:${idPart}`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Creates a URL-safe hash-based identifier from a string
|
|
241
|
+
*/
|
|
242
|
+
private hashIdentifier(input: string): string {
|
|
243
|
+
// Simple hash for identifier generation (not cryptographic)
|
|
244
|
+
let hash = 0;
|
|
245
|
+
for (let i = 0; i < input.length; i++) {
|
|
246
|
+
const char = input.charCodeAt(i);
|
|
247
|
+
hash = ((hash << 5) - hash) + char;
|
|
248
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
249
|
+
}
|
|
250
|
+
return Math.abs(hash).toString(36);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Derives the current asset state by replaying all events in the log.
|
|
255
|
+
*
|
|
256
|
+
* @param log - The event log to derive state from
|
|
257
|
+
* @returns The current AssetState derived from replaying events
|
|
258
|
+
*/
|
|
259
|
+
getCurrentState(log: EventLog): AssetState {
|
|
260
|
+
// Validate input log
|
|
261
|
+
if (!log || !log.events || log.events.length === 0) {
|
|
262
|
+
throw new Error('Cannot get state from an empty event log');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// First event must be a create event
|
|
266
|
+
const createEvent = log.events[0];
|
|
267
|
+
if (createEvent.type !== 'create') {
|
|
268
|
+
throw new Error('First event must be a create event');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Extract initial state from create event
|
|
272
|
+
const createData = createEvent.data as Record<string, unknown>;
|
|
273
|
+
|
|
274
|
+
// Initialize state from create event
|
|
275
|
+
const state: AssetState = {
|
|
276
|
+
did: createData.did as string,
|
|
277
|
+
name: createData.name as string | undefined,
|
|
278
|
+
layer: (createData.layer as 'peer' | 'webvh' | 'btco') || 'peer',
|
|
279
|
+
resources: (createData.resources as ExternalReference[]) || [],
|
|
280
|
+
creator: createData.creator as string | undefined,
|
|
281
|
+
createdAt: createData.createdAt as string | undefined,
|
|
282
|
+
updatedAt: undefined,
|
|
283
|
+
deactivated: false,
|
|
284
|
+
metadata: {},
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// Apply subsequent events
|
|
288
|
+
for (let i = 1; i < log.events.length; i++) {
|
|
289
|
+
const event = log.events[i];
|
|
290
|
+
|
|
291
|
+
if (event.type === 'update') {
|
|
292
|
+
const updateData = event.data as Record<string, unknown>;
|
|
293
|
+
|
|
294
|
+
// Check if this is a migration event
|
|
295
|
+
if (updateData.targetDid && updateData.layer) {
|
|
296
|
+
// Migration event - update DID and layer
|
|
297
|
+
state.did = updateData.targetDid as string;
|
|
298
|
+
state.layer = updateData.layer as 'peer' | 'webvh' | 'btco';
|
|
299
|
+
state.updatedAt = updateData.migratedAt as string;
|
|
300
|
+
|
|
301
|
+
// Store migration info in metadata
|
|
302
|
+
state.metadata = state.metadata || {};
|
|
303
|
+
state.metadata.sourceDid = updateData.sourceDid;
|
|
304
|
+
state.metadata.domain = updateData.domain;
|
|
305
|
+
} else {
|
|
306
|
+
// Regular update event
|
|
307
|
+
if (updateData.name !== undefined) {
|
|
308
|
+
state.name = updateData.name as string;
|
|
309
|
+
}
|
|
310
|
+
if (updateData.resources !== undefined) {
|
|
311
|
+
state.resources = updateData.resources as ExternalReference[];
|
|
312
|
+
}
|
|
313
|
+
if (updateData.updatedAt !== undefined) {
|
|
314
|
+
state.updatedAt = updateData.updatedAt as string;
|
|
315
|
+
}
|
|
316
|
+
if (updateData.did !== undefined) {
|
|
317
|
+
state.did = updateData.did as string;
|
|
318
|
+
}
|
|
319
|
+
if (updateData.layer !== undefined) {
|
|
320
|
+
state.layer = updateData.layer as 'peer' | 'webvh' | 'btco';
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Store other fields in metadata
|
|
325
|
+
for (const [key, value] of Object.entries(updateData)) {
|
|
326
|
+
if (!['name', 'resources', 'updatedAt', 'did', 'layer', 'creator', 'createdAt', 'sourceDid', 'targetDid', 'domain', 'migratedAt'].includes(key)) {
|
|
327
|
+
state.metadata = state.metadata || {};
|
|
328
|
+
state.metadata[key] = value;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
} else if (event.type === 'deactivate') {
|
|
332
|
+
state.deactivated = true;
|
|
333
|
+
|
|
334
|
+
const deactivateData = event.data as Record<string, unknown>;
|
|
335
|
+
if (deactivateData.deactivatedAt !== undefined) {
|
|
336
|
+
state.updatedAt = deactivateData.deactivatedAt as string;
|
|
337
|
+
}
|
|
338
|
+
if (deactivateData.reason !== undefined) {
|
|
339
|
+
state.metadata = state.metadata || {};
|
|
340
|
+
state.metadata.deactivationReason = deactivateData.reason;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return state;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Gets the domain this manager is configured for
|
|
350
|
+
*/
|
|
351
|
+
get domainName(): string {
|
|
352
|
+
return this.domain;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Gets the number of configured witnesses
|
|
357
|
+
*/
|
|
358
|
+
get witnessCount(): number {
|
|
359
|
+
return this.witnesses.length;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CEL Layer Managers
|
|
3
|
+
*
|
|
4
|
+
* Layer managers handle CEL-based asset creation and management at different
|
|
5
|
+
* trust/persistence layers of the Originals Protocol:
|
|
6
|
+
*
|
|
7
|
+
* - PeerCelManager: Layer 0 (did:peer) - Local control, no witnesses
|
|
8
|
+
* - WebVHCelManager: Layer 1 (did:webvh) - HTTP-based witnessing
|
|
9
|
+
* - BtcoCelManager: Layer 2 (did:btco) - Bitcoin-based witnessing
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Export everything from PeerCelManager including CelSigner type
|
|
13
|
+
export * from './PeerCelManager';
|
|
14
|
+
|
|
15
|
+
// Export specific items from WebVHCelManager (CelSigner is imported from PeerCelManager)
|
|
16
|
+
export {
|
|
17
|
+
WebVHCelManager,
|
|
18
|
+
type WebVHCelConfig,
|
|
19
|
+
type WebVHMigrationData
|
|
20
|
+
} from './WebVHCelManager';
|
|
21
|
+
|
|
22
|
+
// Export specific items from BtcoCelManager (CelSigner is imported from PeerCelManager)
|
|
23
|
+
export {
|
|
24
|
+
BtcoCelManager,
|
|
25
|
+
type BtcoCelConfig,
|
|
26
|
+
type BtcoMigrationData
|
|
27
|
+
} from './BtcoCelManager';
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CBOR Serialization for CEL Event Logs
|
|
3
|
+
*
|
|
4
|
+
* Provides compact binary serialization and parsing of EventLog objects using CBOR format.
|
|
5
|
+
* CBOR provides ~50% size reduction compared to JSON for bandwidth-sensitive applications.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { EventLog, LogEntry, DataIntegrityProof, WitnessProof } from '../types';
|
|
9
|
+
import { encode, decode } from '../../utils/cbor';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check if a proof object is a WitnessProof (has witnessedAt field)
|
|
13
|
+
*/
|
|
14
|
+
function isWitnessProof(proof: DataIntegrityProof | WitnessProof): proof is WitnessProof {
|
|
15
|
+
return 'witnessedAt' in proof && typeof (proof as WitnessProof).witnessedAt === 'string';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validate and reconstruct a DataIntegrityProof or WitnessProof
|
|
20
|
+
*/
|
|
21
|
+
function parseProof(proof: unknown): DataIntegrityProof | WitnessProof {
|
|
22
|
+
if (!proof || typeof proof !== 'object') {
|
|
23
|
+
throw new Error('Invalid proof: must be an object');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const p = proof as Record<string, unknown>;
|
|
27
|
+
|
|
28
|
+
// Validate required DataIntegrityProof fields
|
|
29
|
+
if (typeof p.type !== 'string') {
|
|
30
|
+
throw new Error('Invalid proof: missing or invalid type');
|
|
31
|
+
}
|
|
32
|
+
if (typeof p.cryptosuite !== 'string') {
|
|
33
|
+
throw new Error('Invalid proof: missing or invalid cryptosuite');
|
|
34
|
+
}
|
|
35
|
+
if (typeof p.created !== 'string') {
|
|
36
|
+
throw new Error('Invalid proof: missing or invalid created');
|
|
37
|
+
}
|
|
38
|
+
if (typeof p.verificationMethod !== 'string') {
|
|
39
|
+
throw new Error('Invalid proof: missing or invalid verificationMethod');
|
|
40
|
+
}
|
|
41
|
+
if (typeof p.proofPurpose !== 'string') {
|
|
42
|
+
throw new Error('Invalid proof: missing or invalid proofPurpose');
|
|
43
|
+
}
|
|
44
|
+
if (typeof p.proofValue !== 'string') {
|
|
45
|
+
throw new Error('Invalid proof: missing or invalid proofValue');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const baseProof: DataIntegrityProof = {
|
|
49
|
+
type: p.type,
|
|
50
|
+
cryptosuite: p.cryptosuite,
|
|
51
|
+
created: p.created,
|
|
52
|
+
verificationMethod: p.verificationMethod,
|
|
53
|
+
proofPurpose: p.proofPurpose,
|
|
54
|
+
proofValue: p.proofValue,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Check for WitnessProof
|
|
58
|
+
if ('witnessedAt' in p) {
|
|
59
|
+
if (typeof p.witnessedAt !== 'string') {
|
|
60
|
+
throw new Error('Invalid witness proof: witnessedAt must be a string');
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
...baseProof,
|
|
64
|
+
witnessedAt: p.witnessedAt,
|
|
65
|
+
} as WitnessProof;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return baseProof;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Validate and reconstruct a LogEntry
|
|
73
|
+
*/
|
|
74
|
+
function parseEntry(entry: unknown): LogEntry {
|
|
75
|
+
if (!entry || typeof entry !== 'object') {
|
|
76
|
+
throw new Error('Invalid entry: must be an object');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const e = entry as Record<string, unknown>;
|
|
80
|
+
|
|
81
|
+
// Validate type
|
|
82
|
+
if (e.type !== 'create' && e.type !== 'update' && e.type !== 'deactivate') {
|
|
83
|
+
throw new Error(`Invalid entry type: ${e.type}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Validate proof array
|
|
87
|
+
if (!Array.isArray(e.proof)) {
|
|
88
|
+
throw new Error('Invalid entry: proof must be an array');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const parsedEntry: LogEntry = {
|
|
92
|
+
type: e.type,
|
|
93
|
+
data: e.data,
|
|
94
|
+
proof: e.proof.map(parseProof),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// Optional previousEvent
|
|
98
|
+
if (e.previousEvent !== undefined) {
|
|
99
|
+
if (typeof e.previousEvent !== 'string') {
|
|
100
|
+
throw new Error('Invalid entry: previousEvent must be a string');
|
|
101
|
+
}
|
|
102
|
+
parsedEntry.previousEvent = e.previousEvent;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return parsedEntry;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Serialize an EventLog to CBOR binary format.
|
|
110
|
+
*
|
|
111
|
+
* CBOR provides a compact binary representation that is typically
|
|
112
|
+
* 30-50% smaller than JSON for event logs.
|
|
113
|
+
*
|
|
114
|
+
* @param log - The EventLog to serialize
|
|
115
|
+
* @returns Uint8Array containing the CBOR-encoded EventLog
|
|
116
|
+
* @throws Error if log is null or undefined
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const log = await createEventLog(data, options);
|
|
121
|
+
* const cbor = serializeEventLogCbor(log);
|
|
122
|
+
* console.log(cbor.length); // compact binary size
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export function serializeEventLogCbor(log: EventLog): Uint8Array {
|
|
126
|
+
if (!log) {
|
|
127
|
+
throw new Error('Cannot serialize null or undefined EventLog');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return encode(log);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Parse a CBOR binary into an EventLog.
|
|
135
|
+
*
|
|
136
|
+
* Validates the structure and types of the parsed object.
|
|
137
|
+
*
|
|
138
|
+
* @param cbor - CBOR binary data to parse
|
|
139
|
+
* @returns Parsed and validated EventLog
|
|
140
|
+
* @throws Error if CBOR is invalid or doesn't match EventLog structure
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* const cbor = readFileSync('asset.cel.cbor');
|
|
145
|
+
* const log = parseEventLogCbor(cbor);
|
|
146
|
+
* console.log(log.events.length);
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export function parseEventLogCbor(cbor: Uint8Array): EventLog {
|
|
150
|
+
if (!cbor || !(cbor instanceof Uint8Array)) {
|
|
151
|
+
throw new Error('Cannot parse null, undefined, or non-Uint8Array value');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (cbor.length === 0) {
|
|
155
|
+
throw new Error('Cannot parse empty CBOR data');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let parsed: unknown;
|
|
159
|
+
try {
|
|
160
|
+
parsed = decode(cbor);
|
|
161
|
+
} catch (e) {
|
|
162
|
+
throw new Error(`Invalid CBOR: ${(e as Error).message}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
166
|
+
throw new Error('Invalid EventLog: must be an object');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const obj = parsed as Record<string, unknown>;
|
|
170
|
+
|
|
171
|
+
// Validate events array
|
|
172
|
+
if (!Array.isArray(obj.events)) {
|
|
173
|
+
throw new Error('Invalid EventLog: events must be an array');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const eventLog: EventLog = {
|
|
177
|
+
events: obj.events.map(parseEntry),
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Optional previousLog
|
|
181
|
+
if (obj.previousLog !== undefined) {
|
|
182
|
+
if (typeof obj.previousLog !== 'string') {
|
|
183
|
+
throw new Error('Invalid EventLog: previousLog must be a string');
|
|
184
|
+
}
|
|
185
|
+
eventLog.previousLog = obj.previousLog;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return eventLog;
|
|
189
|
+
}
|