@originals/sdk 1.4.5 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/adapters/FeeOracleMock.js +2 -2
  2. package/dist/bitcoin/OrdinalsClient.d.ts +1 -1
  3. package/dist/bitcoin/OrdinalsClient.js +10 -8
  4. package/dist/bitcoin/PSBTBuilder.js +1 -1
  5. package/dist/bitcoin/utxo-selection.js +2 -2
  6. package/dist/cel/ExternalReferenceManager.d.ts +57 -0
  7. package/dist/cel/ExternalReferenceManager.js +73 -0
  8. package/dist/cel/OriginalsCel.d.ts +245 -0
  9. package/dist/cel/OriginalsCel.js +349 -0
  10. package/dist/cel/algorithms/createEventLog.d.ts +32 -0
  11. package/dist/cel/algorithms/createEventLog.js +56 -0
  12. package/dist/cel/algorithms/deactivateEventLog.d.ts +35 -0
  13. package/dist/cel/algorithms/deactivateEventLog.js +91 -0
  14. package/dist/cel/algorithms/index.d.ts +10 -0
  15. package/dist/cel/algorithms/index.js +10 -0
  16. package/dist/cel/algorithms/updateEventLog.d.ts +34 -0
  17. package/dist/cel/algorithms/updateEventLog.js +82 -0
  18. package/dist/cel/algorithms/verifyEventLog.d.ts +45 -0
  19. package/dist/cel/algorithms/verifyEventLog.js +255 -0
  20. package/dist/cel/algorithms/witnessEvent.d.ts +29 -0
  21. package/dist/cel/algorithms/witnessEvent.js +75 -0
  22. package/dist/cel/cli/create.d.ts +36 -0
  23. package/dist/cel/cli/create.js +282 -0
  24. package/dist/cel/cli/index.d.ts +11 -0
  25. package/dist/cel/cli/index.js +351 -0
  26. package/dist/cel/cli/inspect.d.ts +30 -0
  27. package/dist/cel/cli/inspect.js +475 -0
  28. package/dist/cel/cli/migrate.d.ts +41 -0
  29. package/dist/cel/cli/migrate.js +405 -0
  30. package/dist/cel/cli/verify.d.ts +31 -0
  31. package/dist/cel/cli/verify.js +205 -0
  32. package/dist/cel/hash.d.ts +46 -0
  33. package/dist/cel/hash.js +66 -0
  34. package/dist/cel/index.d.ts +15 -0
  35. package/dist/cel/index.js +15 -0
  36. package/dist/cel/layers/BtcoCelManager.d.ts +121 -0
  37. package/dist/cel/layers/BtcoCelManager.js +329 -0
  38. package/dist/cel/layers/PeerCelManager.d.ts +151 -0
  39. package/dist/cel/layers/PeerCelManager.js +299 -0
  40. package/dist/cel/layers/WebVHCelManager.d.ts +122 -0
  41. package/dist/cel/layers/WebVHCelManager.js +291 -0
  42. package/dist/cel/layers/index.d.ts +13 -0
  43. package/dist/cel/layers/index.js +16 -0
  44. package/dist/cel/serialization/cbor.d.ts +42 -0
  45. package/dist/cel/serialization/cbor.js +163 -0
  46. package/dist/cel/serialization/index.d.ts +9 -0
  47. package/dist/cel/serialization/index.js +9 -0
  48. package/dist/cel/serialization/json.d.ts +41 -0
  49. package/dist/cel/serialization/json.js +180 -0
  50. package/dist/cel/types.d.ts +149 -0
  51. package/dist/cel/types.js +7 -0
  52. package/dist/cel/witnesses/BitcoinWitness.d.ts +83 -0
  53. package/dist/cel/witnesses/BitcoinWitness.js +116 -0
  54. package/dist/cel/witnesses/HttpWitness.d.ts +79 -0
  55. package/dist/cel/witnesses/HttpWitness.js +163 -0
  56. package/dist/cel/witnesses/WitnessService.d.ts +49 -0
  57. package/dist/cel/witnesses/WitnessService.js +10 -0
  58. package/dist/cel/witnesses/index.d.ts +10 -0
  59. package/dist/cel/witnesses/index.js +7 -0
  60. package/dist/core/OriginalsSDK.js +5 -1
  61. package/dist/crypto/Signer.js +14 -6
  62. package/dist/crypto/noble-init.js +20 -1
  63. package/dist/did/BtcoDidResolver.d.ts +2 -2
  64. package/dist/did/BtcoDidResolver.js +12 -8
  65. package/dist/did/DIDManager.js +6 -4
  66. package/dist/did/KeyManager.d.ts +1 -1
  67. package/dist/did/KeyManager.js +7 -4
  68. package/dist/did/WebVHManager.js +1 -1
  69. package/dist/did/createBtcoDidDocument.js +2 -1
  70. package/dist/events/types.d.ts +4 -1
  71. package/dist/examples/create-module-original.js +1 -1
  72. package/dist/examples/full-lifecycle-flow.js +2 -2
  73. package/dist/index.d.ts +13 -0
  74. package/dist/index.js +12 -0
  75. package/dist/kinds/KindRegistry.js +59 -29
  76. package/dist/lifecycle/BatchOperations.d.ts +5 -3
  77. package/dist/lifecycle/BatchOperations.js +11 -5
  78. package/dist/lifecycle/LifecycleManager.d.ts +1 -1
  79. package/dist/lifecycle/LifecycleManager.js +42 -33
  80. package/dist/lifecycle/OriginalsAsset.js +2 -2
  81. package/dist/migration/MigrationManager.js +67 -3
  82. package/dist/storage/LocalStorageAdapter.js +4 -1
  83. package/dist/storage/MemoryStorageAdapter.js +7 -7
  84. package/dist/types/network.js +6 -3
  85. package/dist/utils/Logger.d.ts +6 -6
  86. package/dist/utils/Logger.js +5 -3
  87. package/dist/utils/MetricsCollector.js +1 -1
  88. package/dist/utils/bitcoin-address.js +4 -2
  89. package/dist/utils/cbor.js +16 -3
  90. package/dist/utils/encoding.d.ts +4 -4
  91. package/dist/utils/encoding.js +7 -6
  92. package/dist/utils/hash.js +6 -1
  93. package/dist/utils/serialization.d.ts +2 -2
  94. package/dist/utils/serialization.js +7 -5
  95. package/dist/utils/telemetry.js +6 -2
  96. package/dist/utils/validation.js +8 -4
  97. package/dist/vc/CredentialManager.d.ts +8 -8
  98. package/dist/vc/CredentialManager.js +46 -33
  99. package/dist/vc/Issuer.d.ts +2 -2
  100. package/dist/vc/Issuer.js +5 -1
  101. package/dist/vc/Verifier.d.ts +2 -2
  102. package/dist/vc/Verifier.js +12 -6
  103. package/dist/vc/documentLoader.d.ts +5 -3
  104. package/dist/vc/documentLoader.js +5 -4
  105. package/package.json +4 -1
@@ -0,0 +1,291 @@
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
+ import { updateEventLog } from '../algorithms/updateEventLog';
13
+ import { witnessEvent } from '../algorithms/witnessEvent';
14
+ /**
15
+ * WebVHCelManager - Manages CEL-based asset migration to did:webvh layer
16
+ *
17
+ * The webvh layer is the first publication layer for Originals assets.
18
+ * Assets at this layer:
19
+ * - Have a did:webvh identifier based on a domain
20
+ * - Can have HTTP-based witness attestations
21
+ * - Are discoverable via web-based DID resolution
22
+ * - Can be further migrated to did:btco layer
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const httpWitness = new HttpWitness('https://witness.example.com/api/attest');
27
+ * const manager = new WebVHCelManager(
28
+ * async (data) => createEdDsaProof(data, privateKey),
29
+ * 'example.com',
30
+ * [httpWitness]
31
+ * );
32
+ *
33
+ * const webvhLog = await manager.migrate(peerLog);
34
+ * ```
35
+ */
36
+ export class WebVHCelManager {
37
+ /**
38
+ * Creates a new WebVHCelManager instance
39
+ *
40
+ * @param signer - Function that signs data and returns a DataIntegrityProof
41
+ * @param domain - The domain for the did:webvh DID (e.g., 'example.com')
42
+ * @param witnesses - Optional array of witness services for attestations
43
+ * @param config - Optional configuration options
44
+ */
45
+ constructor(signer, domain, witnesses = [], config = {}) {
46
+ if (typeof signer !== 'function') {
47
+ throw new Error('WebVHCelManager requires a signer function');
48
+ }
49
+ if (!domain || typeof domain !== 'string') {
50
+ throw new Error('WebVHCelManager requires a valid domain string');
51
+ }
52
+ // Basic domain validation
53
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$/.test(domain) && !/^[a-zA-Z0-9]$/.test(domain)) {
54
+ throw new Error(`Invalid domain format: ${domain}`);
55
+ }
56
+ if (!Array.isArray(witnesses)) {
57
+ throw new Error('witnesses must be an array');
58
+ }
59
+ this.signer = signer;
60
+ this.domain = domain;
61
+ this.witnesses = witnesses;
62
+ this.config = {
63
+ proofPurpose: 'assertionMethod',
64
+ ...config,
65
+ };
66
+ }
67
+ /**
68
+ * Migrates a peer layer event log to the did:webvh layer
69
+ *
70
+ * This method:
71
+ * 1. Validates the input log (must have a create event with peer layer data)
72
+ * 2. Generates a new did:webvh DID based on the domain
73
+ * 3. Creates an update event with migration data
74
+ * 4. Optionally adds witness proofs from configured witnesses
75
+ * 5. Returns the updated EventLog
76
+ *
77
+ * @param peerLog - The event log from the peer layer to migrate
78
+ * @returns Promise resolving to an EventLog with the migration event appended
79
+ *
80
+ * @throws Error if the log is empty, deactivated, or not from peer layer
81
+ * @throws Error if signer produces invalid proof
82
+ * @throws Error if witness service fails (if witnesses configured)
83
+ */
84
+ async migrate(peerLog) {
85
+ // Validate input log
86
+ if (!peerLog || !peerLog.events || peerLog.events.length === 0) {
87
+ throw new Error('Cannot migrate an empty event log');
88
+ }
89
+ // Get the create event to extract source DID
90
+ const createEvent = peerLog.events[0];
91
+ if (createEvent.type !== 'create') {
92
+ throw new Error('First event must be a create event');
93
+ }
94
+ // Extract source data
95
+ const createData = createEvent.data;
96
+ const sourceDid = createData.did;
97
+ if (!sourceDid) {
98
+ throw new Error('Create event must have a did field');
99
+ }
100
+ // Validate source is from peer layer
101
+ const sourceLayer = createData.layer;
102
+ if (sourceLayer && sourceLayer !== 'peer') {
103
+ throw new Error(`Cannot migrate from ${sourceLayer} layer to webvh layer. Expected peer layer.`);
104
+ }
105
+ // Check if log is already deactivated
106
+ const lastEvent = peerLog.events[peerLog.events.length - 1];
107
+ if (lastEvent.type === 'deactivate') {
108
+ throw new Error('Cannot migrate a deactivated event log');
109
+ }
110
+ // Generate did:webvh DID
111
+ const targetDid = this.generateWebVHDid(sourceDid);
112
+ // Prepare migration data
113
+ const migrationData = {
114
+ sourceDid,
115
+ targetDid,
116
+ layer: 'webvh',
117
+ domain: this.domain,
118
+ migratedAt: new Date().toISOString(),
119
+ };
120
+ // Build update options
121
+ const updateOptions = {
122
+ signer: this.signer,
123
+ verificationMethod: this.config.verificationMethod || `${targetDid}#key-0`,
124
+ proofPurpose: this.config.proofPurpose,
125
+ };
126
+ // Create the update event with migration data
127
+ let updatedLog = await updateEventLog(peerLog, migrationData, updateOptions);
128
+ // Add witness proofs if witnesses are configured
129
+ if (this.witnesses.length > 0) {
130
+ // Get the last event (the migration event we just added)
131
+ const lastEventIndex = updatedLog.events.length - 1;
132
+ let witnessedEvent = updatedLog.events[lastEventIndex];
133
+ // Add witness proofs from each configured witness
134
+ for (const witness of this.witnesses) {
135
+ witnessedEvent = await witnessEvent(witnessedEvent, witness);
136
+ }
137
+ // Replace the last event with the witnessed version
138
+ updatedLog = {
139
+ ...updatedLog,
140
+ events: [
141
+ ...updatedLog.events.slice(0, lastEventIndex),
142
+ witnessedEvent,
143
+ ],
144
+ };
145
+ }
146
+ return updatedLog;
147
+ }
148
+ /**
149
+ * Generates a did:webvh DID for this domain
150
+ *
151
+ * The did:webvh format is: did:webvh:{domain}:{id}
152
+ * where {id} is derived from the source DID to maintain linkage.
153
+ *
154
+ * @param sourceDid - The source DID to derive the webvh DID from
155
+ * @returns A did:webvh string
156
+ */
157
+ generateWebVHDid(sourceDid) {
158
+ // Extract a stable identifier from the source DID
159
+ // For did:peer, extract the key portion after the method
160
+ let idPart;
161
+ if (sourceDid.startsWith('did:peer:')) {
162
+ // For peer DIDs, use a hash-derived portion
163
+ // did:peer:4zQm... -> use the multibase portion
164
+ const peerPart = sourceDid.replace('did:peer:', '');
165
+ // Take first 32 chars of the peer DID identifier for brevity
166
+ idPart = peerPart.substring(0, Math.min(32, peerPart.length));
167
+ }
168
+ else if (sourceDid.startsWith('did:key:')) {
169
+ // For key DIDs, extract the key portion
170
+ idPart = sourceDid.replace('did:key:', '').substring(0, 32);
171
+ }
172
+ else {
173
+ // For other DIDs, create a hash-based identifier
174
+ idPart = this.hashIdentifier(sourceDid);
175
+ }
176
+ // Sanitize for URL safety (replace invalid chars)
177
+ idPart = idPart.replace(/[^a-zA-Z0-9]/g, '');
178
+ return `did:webvh:${this.domain}:${idPart}`;
179
+ }
180
+ /**
181
+ * Creates a URL-safe hash-based identifier from a string
182
+ */
183
+ hashIdentifier(input) {
184
+ // Simple hash for identifier generation (not cryptographic)
185
+ let hash = 0;
186
+ for (let i = 0; i < input.length; i++) {
187
+ const char = input.charCodeAt(i);
188
+ hash = ((hash << 5) - hash) + char;
189
+ hash = hash & hash; // Convert to 32bit integer
190
+ }
191
+ return Math.abs(hash).toString(36);
192
+ }
193
+ /**
194
+ * Derives the current asset state by replaying all events in the log.
195
+ *
196
+ * @param log - The event log to derive state from
197
+ * @returns The current AssetState derived from replaying events
198
+ */
199
+ getCurrentState(log) {
200
+ // Validate input log
201
+ if (!log || !log.events || log.events.length === 0) {
202
+ throw new Error('Cannot get state from an empty event log');
203
+ }
204
+ // First event must be a create event
205
+ const createEvent = log.events[0];
206
+ if (createEvent.type !== 'create') {
207
+ throw new Error('First event must be a create event');
208
+ }
209
+ // Extract initial state from create event
210
+ const createData = createEvent.data;
211
+ // Initialize state from create event
212
+ const state = {
213
+ did: createData.did,
214
+ name: createData.name,
215
+ layer: createData.layer || 'peer',
216
+ resources: createData.resources || [],
217
+ creator: createData.creator,
218
+ createdAt: createData.createdAt,
219
+ updatedAt: undefined,
220
+ deactivated: false,
221
+ metadata: {},
222
+ };
223
+ // Apply subsequent events
224
+ for (let i = 1; i < log.events.length; i++) {
225
+ const event = log.events[i];
226
+ if (event.type === 'update') {
227
+ const updateData = event.data;
228
+ // Check if this is a migration event
229
+ if (updateData.targetDid && updateData.layer) {
230
+ // Migration event - update DID and layer
231
+ state.did = updateData.targetDid;
232
+ state.layer = updateData.layer;
233
+ state.updatedAt = updateData.migratedAt;
234
+ // Store migration info in metadata
235
+ state.metadata = state.metadata || {};
236
+ state.metadata.sourceDid = updateData.sourceDid;
237
+ state.metadata.domain = updateData.domain;
238
+ }
239
+ else {
240
+ // Regular update event
241
+ if (updateData.name !== undefined) {
242
+ state.name = updateData.name;
243
+ }
244
+ if (updateData.resources !== undefined) {
245
+ state.resources = updateData.resources;
246
+ }
247
+ if (updateData.updatedAt !== undefined) {
248
+ state.updatedAt = updateData.updatedAt;
249
+ }
250
+ if (updateData.did !== undefined) {
251
+ state.did = updateData.did;
252
+ }
253
+ if (updateData.layer !== undefined) {
254
+ state.layer = updateData.layer;
255
+ }
256
+ }
257
+ // Store other fields in metadata
258
+ for (const [key, value] of Object.entries(updateData)) {
259
+ if (!['name', 'resources', 'updatedAt', 'did', 'layer', 'creator', 'createdAt', 'sourceDid', 'targetDid', 'domain', 'migratedAt'].includes(key)) {
260
+ state.metadata = state.metadata || {};
261
+ state.metadata[key] = value;
262
+ }
263
+ }
264
+ }
265
+ else if (event.type === 'deactivate') {
266
+ state.deactivated = true;
267
+ const deactivateData = event.data;
268
+ if (deactivateData.deactivatedAt !== undefined) {
269
+ state.updatedAt = deactivateData.deactivatedAt;
270
+ }
271
+ if (deactivateData.reason !== undefined) {
272
+ state.metadata = state.metadata || {};
273
+ state.metadata.deactivationReason = deactivateData.reason;
274
+ }
275
+ }
276
+ }
277
+ return state;
278
+ }
279
+ /**
280
+ * Gets the domain this manager is configured for
281
+ */
282
+ get domainName() {
283
+ return this.domain;
284
+ }
285
+ /**
286
+ * Gets the number of configured witnesses
287
+ */
288
+ get witnessCount() {
289
+ return this.witnesses.length;
290
+ }
291
+ }
@@ -0,0 +1,13 @@
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
+ export * from './PeerCelManager';
12
+ export { WebVHCelManager, type WebVHCelConfig, type WebVHMigrationData } from './WebVHCelManager';
13
+ export { BtcoCelManager, type BtcoCelConfig, type BtcoMigrationData } from './BtcoCelManager';
@@ -0,0 +1,16 @@
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
+ // Export everything from PeerCelManager including CelSigner type
12
+ export * from './PeerCelManager';
13
+ // Export specific items from WebVHCelManager (CelSigner is imported from PeerCelManager)
14
+ export { WebVHCelManager } from './WebVHCelManager';
15
+ // Export specific items from BtcoCelManager (CelSigner is imported from PeerCelManager)
16
+ export { BtcoCelManager } from './BtcoCelManager';
@@ -0,0 +1,42 @@
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
+ import type { EventLog } from '../types';
8
+ /**
9
+ * Serialize an EventLog to CBOR binary format.
10
+ *
11
+ * CBOR provides a compact binary representation that is typically
12
+ * 30-50% smaller than JSON for event logs.
13
+ *
14
+ * @param log - The EventLog to serialize
15
+ * @returns Uint8Array containing the CBOR-encoded EventLog
16
+ * @throws Error if log is null or undefined
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const log = await createEventLog(data, options);
21
+ * const cbor = serializeEventLogCbor(log);
22
+ * console.log(cbor.length); // compact binary size
23
+ * ```
24
+ */
25
+ export declare function serializeEventLogCbor(log: EventLog): Uint8Array;
26
+ /**
27
+ * Parse a CBOR binary into an EventLog.
28
+ *
29
+ * Validates the structure and types of the parsed object.
30
+ *
31
+ * @param cbor - CBOR binary data to parse
32
+ * @returns Parsed and validated EventLog
33
+ * @throws Error if CBOR is invalid or doesn't match EventLog structure
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * const cbor = readFileSync('asset.cel.cbor');
38
+ * const log = parseEventLogCbor(cbor);
39
+ * console.log(log.events.length);
40
+ * ```
41
+ */
42
+ export declare function parseEventLogCbor(cbor: Uint8Array): EventLog;
@@ -0,0 +1,163 @@
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
+ import { encode, decode } from '../../utils/cbor';
8
+ /**
9
+ * Check if a proof object is a WitnessProof (has witnessedAt field)
10
+ */
11
+ function isWitnessProof(proof) {
12
+ return 'witnessedAt' in proof && typeof proof.witnessedAt === 'string';
13
+ }
14
+ /**
15
+ * Validate and reconstruct a DataIntegrityProof or WitnessProof
16
+ */
17
+ function parseProof(proof) {
18
+ if (!proof || typeof proof !== 'object') {
19
+ throw new Error('Invalid proof: must be an object');
20
+ }
21
+ const p = proof;
22
+ // Validate required DataIntegrityProof fields
23
+ if (typeof p.type !== 'string') {
24
+ throw new Error('Invalid proof: missing or invalid type');
25
+ }
26
+ if (typeof p.cryptosuite !== 'string') {
27
+ throw new Error('Invalid proof: missing or invalid cryptosuite');
28
+ }
29
+ if (typeof p.created !== 'string') {
30
+ throw new Error('Invalid proof: missing or invalid created');
31
+ }
32
+ if (typeof p.verificationMethod !== 'string') {
33
+ throw new Error('Invalid proof: missing or invalid verificationMethod');
34
+ }
35
+ if (typeof p.proofPurpose !== 'string') {
36
+ throw new Error('Invalid proof: missing or invalid proofPurpose');
37
+ }
38
+ if (typeof p.proofValue !== 'string') {
39
+ throw new Error('Invalid proof: missing or invalid proofValue');
40
+ }
41
+ const baseProof = {
42
+ type: p.type,
43
+ cryptosuite: p.cryptosuite,
44
+ created: p.created,
45
+ verificationMethod: p.verificationMethod,
46
+ proofPurpose: p.proofPurpose,
47
+ proofValue: p.proofValue,
48
+ };
49
+ // Check for WitnessProof
50
+ if ('witnessedAt' in p) {
51
+ if (typeof p.witnessedAt !== 'string') {
52
+ throw new Error('Invalid witness proof: witnessedAt must be a string');
53
+ }
54
+ return {
55
+ ...baseProof,
56
+ witnessedAt: p.witnessedAt,
57
+ };
58
+ }
59
+ return baseProof;
60
+ }
61
+ /**
62
+ * Validate and reconstruct a LogEntry
63
+ */
64
+ function parseEntry(entry) {
65
+ if (!entry || typeof entry !== 'object') {
66
+ throw new Error('Invalid entry: must be an object');
67
+ }
68
+ const e = entry;
69
+ // Validate type
70
+ if (e.type !== 'create' && e.type !== 'update' && e.type !== 'deactivate') {
71
+ throw new Error(`Invalid entry type: ${e.type}`);
72
+ }
73
+ // Validate proof array
74
+ if (!Array.isArray(e.proof)) {
75
+ throw new Error('Invalid entry: proof must be an array');
76
+ }
77
+ const parsedEntry = {
78
+ type: e.type,
79
+ data: e.data,
80
+ proof: e.proof.map(parseProof),
81
+ };
82
+ // Optional previousEvent
83
+ if (e.previousEvent !== undefined) {
84
+ if (typeof e.previousEvent !== 'string') {
85
+ throw new Error('Invalid entry: previousEvent must be a string');
86
+ }
87
+ parsedEntry.previousEvent = e.previousEvent;
88
+ }
89
+ return parsedEntry;
90
+ }
91
+ /**
92
+ * Serialize an EventLog to CBOR binary format.
93
+ *
94
+ * CBOR provides a compact binary representation that is typically
95
+ * 30-50% smaller than JSON for event logs.
96
+ *
97
+ * @param log - The EventLog to serialize
98
+ * @returns Uint8Array containing the CBOR-encoded EventLog
99
+ * @throws Error if log is null or undefined
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const log = await createEventLog(data, options);
104
+ * const cbor = serializeEventLogCbor(log);
105
+ * console.log(cbor.length); // compact binary size
106
+ * ```
107
+ */
108
+ export function serializeEventLogCbor(log) {
109
+ if (!log) {
110
+ throw new Error('Cannot serialize null or undefined EventLog');
111
+ }
112
+ return encode(log);
113
+ }
114
+ /**
115
+ * Parse a CBOR binary into an EventLog.
116
+ *
117
+ * Validates the structure and types of the parsed object.
118
+ *
119
+ * @param cbor - CBOR binary data to parse
120
+ * @returns Parsed and validated EventLog
121
+ * @throws Error if CBOR is invalid or doesn't match EventLog structure
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * const cbor = readFileSync('asset.cel.cbor');
126
+ * const log = parseEventLogCbor(cbor);
127
+ * console.log(log.events.length);
128
+ * ```
129
+ */
130
+ export function parseEventLogCbor(cbor) {
131
+ if (!cbor || !(cbor instanceof Uint8Array)) {
132
+ throw new Error('Cannot parse null, undefined, or non-Uint8Array value');
133
+ }
134
+ if (cbor.length === 0) {
135
+ throw new Error('Cannot parse empty CBOR data');
136
+ }
137
+ let parsed;
138
+ try {
139
+ parsed = decode(cbor);
140
+ }
141
+ catch (e) {
142
+ throw new Error(`Invalid CBOR: ${e.message}`);
143
+ }
144
+ if (!parsed || typeof parsed !== 'object') {
145
+ throw new Error('Invalid EventLog: must be an object');
146
+ }
147
+ const obj = parsed;
148
+ // Validate events array
149
+ if (!Array.isArray(obj.events)) {
150
+ throw new Error('Invalid EventLog: events must be an array');
151
+ }
152
+ const eventLog = {
153
+ events: obj.events.map(parseEntry),
154
+ };
155
+ // Optional previousLog
156
+ if (obj.previousLog !== undefined) {
157
+ if (typeof obj.previousLog !== 'string') {
158
+ throw new Error('Invalid EventLog: previousLog must be a string');
159
+ }
160
+ eventLog.previousLog = obj.previousLog;
161
+ }
162
+ return eventLog;
163
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * CEL Serialization Module
3
+ *
4
+ * Provides serialization formats for EventLog:
5
+ * - JSON: Human-readable, standard format
6
+ * - CBOR: Compact binary format for bandwidth-sensitive applications
7
+ */
8
+ export * from './json';
9
+ export * from './cbor';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * CEL Serialization Module
3
+ *
4
+ * Provides serialization formats for EventLog:
5
+ * - JSON: Human-readable, standard format
6
+ * - CBOR: Compact binary format for bandwidth-sensitive applications
7
+ */
8
+ export * from './json';
9
+ export * from './cbor';
@@ -0,0 +1,41 @@
1
+ /**
2
+ * JSON Serialization for CEL Event Logs
3
+ *
4
+ * Provides serialization and parsing of EventLog objects to/from JSON format.
5
+ * Uses deterministic key ordering for consistent hashes.
6
+ */
7
+ import type { EventLog } from '../types';
8
+ /**
9
+ * Serialize an EventLog to JSON string.
10
+ *
11
+ * Uses deterministic key ordering for consistent output.
12
+ *
13
+ * @param log - The EventLog to serialize
14
+ * @returns JSON string representation of the EventLog
15
+ * @throws Error if log is null or undefined
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const log = await createEventLog(data, options);
20
+ * const json = serializeEventLogJson(log);
21
+ * console.log(json); // '{"events":[...]}'
22
+ * ```
23
+ */
24
+ export declare function serializeEventLogJson(log: EventLog): string;
25
+ /**
26
+ * Parse a JSON string into an EventLog.
27
+ *
28
+ * Validates the structure and types of the parsed object.
29
+ *
30
+ * @param json - JSON string to parse
31
+ * @returns Parsed and validated EventLog
32
+ * @throws Error if JSON is invalid or doesn't match EventLog structure
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const json = '{"events":[...]}';
37
+ * const log = parseEventLogJson(json);
38
+ * console.log(log.events.length);
39
+ * ```
40
+ */
41
+ export declare function parseEventLogJson(json: string): EventLog;