@lerna-labs/hydra-sdk 1.0.0-beta.21 → 1.0.0-beta.23

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.
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
  import { HydraWebSocket } from './hydra-websocket.js';
3
- import type { GreetingsMessage, HeadStatus, HydraMessage, HydraMonitorOptions, HydraStatus, ServerOutput, TimestampedEvent } from './types.js';
3
+ import type { GreetingsMessage, HeadStatus, HydraHeadInfo, HydraMessage, HydraMonitorOptions, HydraStatus, ServerOutput, TimestampedEvent } from './types.js';
4
4
  /**
5
5
  * Persistent WebSocket monitor for a Hydra head.
6
6
  *
@@ -53,6 +53,12 @@ export declare class HydraMonitor extends EventEmitter {
53
53
  get headStatusMixed(): HeadStatus;
54
54
  /** The full Greetings message from the most recent connection. */
55
55
  get greetings(): GreetingsMessage | null;
56
+ /**
57
+ * Summary of Hydra head info extracted from the last Greetings.
58
+ * Excludes the full UTxO snapshot to keep payloads small.
59
+ * Returns `null` if no Greetings has been received yet.
60
+ */
61
+ get headInfo(): HydraHeadInfo | null;
56
62
  /** The last N events (configurable via eventBufferSize). Most recent last. */
57
63
  get recentEvents(): readonly TimestampedEvent[];
58
64
  /**
@@ -92,6 +92,31 @@ export class HydraMonitor extends EventEmitter {
92
92
  get greetings() {
93
93
  return this.ws.lastGreetings;
94
94
  }
95
+ /**
96
+ * Summary of Hydra head info extracted from the last Greetings.
97
+ * Excludes the full UTxO snapshot to keep payloads small.
98
+ * Returns `null` if no Greetings has been received yet.
99
+ */
100
+ get headInfo() {
101
+ const g = this.greetings;
102
+ if (!g)
103
+ return null;
104
+ const peers = g.env?.configuredPeers;
105
+ const peerCount = peers ? peers.split(',').filter(Boolean).length : 0;
106
+ return {
107
+ headStatus: g.headStatus,
108
+ headId: g.hydraHeadId ?? null,
109
+ nodeVersion: g.hydraNodeVersion ?? null,
110
+ me: g.me.vkey,
111
+ contestationPeriod: g.env?.contestationPeriod ?? null,
112
+ depositPeriod: g.env?.depositPeriod ?? null,
113
+ participants: g.env?.participants ?? [],
114
+ networkConnected: g.networkInfo?.networkConnected ?? false,
115
+ peerCount,
116
+ chainSyncedStatus: g.chainSyncedStatus ?? null,
117
+ currentSlot: g.currentSlot ?? null,
118
+ };
119
+ }
95
120
  /** The last N events (configurable via eventBufferSize). Most recent last. */
96
121
  get recentEvents() {
97
122
  return this._events;
@@ -149,10 +149,19 @@ export class HydraWebSocket extends EventEmitter {
149
149
  return this._lastGreetings;
150
150
  }
151
151
  handleMessage(msg) {
152
+ // Strip sensitive fields before caching or emitting
152
153
  if (msg.tag === 'Greetings') {
153
- this._lastGreetings = msg;
154
+ const sanitized = { ...msg };
155
+ if (sanitized.env && typeof sanitized.env === 'object') {
156
+ const { signingKey: _, ...safeEnv } = sanitized.env;
157
+ sanitized.env = safeEnv;
158
+ }
159
+ this._lastGreetings = sanitized;
160
+ this.emit('message', sanitized);
161
+ }
162
+ else {
163
+ this.emit('message', msg);
154
164
  }
155
- this.emit('message', msg);
156
165
  // Update status from Greetings headStatus
157
166
  if (msg.tag === 'Greetings' && 'headStatus' in msg) {
158
167
  const mapped = HEAD_STATUS_TO_HYDRA[msg.headStatus];
@@ -11,4 +11,4 @@
11
11
  * }
12
12
  * ```
13
13
  */
14
- export type { ClientInput, ClientMessage, ConnectionState, HeadStatus, HydraMessage, HydraMonitorOptions, HydraStatus, HydraTransaction, HydraWsMessage, hydraStatus, hydraTransaction, ServerOutput, TimestampedEvent, } from './types.js';
14
+ export type { ClientInput, ClientMessage, ConfirmedSnapshot, ConnectionState, HeadStatus, HydraHeadInfo, HydraMessage, HydraMonitorOptions, HydraSnapshot, HydraStatus, HydraTransaction, HydraWsMessage, hydraStatus, hydraTransaction, ServerOutput, TimestampedEvent, } from './types.js';
@@ -50,6 +50,28 @@ export type HydraStatus = 'IDLE' | 'INITIALIZING' | 'OPEN' | 'CLOSED' | 'FANOUT_
50
50
  export type hydraStatus = HydraStatus;
51
51
  /** Connection state of the WebSocket. */
52
52
  export type ConnectionState = 'IDLE' | 'CONNECTING' | 'CONNECTED' | 'FAILED' | 'DISCONNECTED';
53
+ /** A confirmed Hydra L2 snapshot. */
54
+ export interface HydraSnapshot {
55
+ headId: string;
56
+ version: number;
57
+ number: number;
58
+ confirmed: HydraTransaction[];
59
+ utxo: HydraUTxOs;
60
+ utxoToCommit: HydraUTxOs | null;
61
+ utxoToDecommit: HydraUTxOs | null;
62
+ }
63
+ /** Multi-party aggregate signature map. */
64
+ export type MultiSignature = Record<string, string>;
65
+ /** Discriminated union for confirmed snapshot variants. */
66
+ export type ConfirmedSnapshot = {
67
+ tag: 'InitialSnapshot';
68
+ headId: string;
69
+ initialUTxO?: HydraUTxOs;
70
+ } | {
71
+ tag: 'ConfirmedSnapshot';
72
+ snapshot: HydraSnapshot;
73
+ signatures: MultiSignature;
74
+ };
53
75
  /** Messages that can be sent to the Hydra node over WebSocket. */
54
76
  export type ClientInput = {
55
77
  tag: 'Init';
@@ -60,17 +82,44 @@ export type ClientInput = {
60
82
  transaction: HydraTransaction;
61
83
  } | {
62
84
  tag: 'Close';
85
+ } | {
86
+ tag: 'SafeClose';
63
87
  } | {
64
88
  tag: 'Contest';
65
89
  } | {
66
90
  tag: 'Fanout';
67
91
  } | {
68
92
  tag: 'Decommit';
69
- transaction: HydraTransaction;
93
+ decommitTx: HydraTransaction;
70
94
  } | {
71
95
  tag: 'Recover';
72
96
  recoverTxId: string;
97
+ } | {
98
+ tag: 'SideLoadSnapshot';
99
+ snapshot: ConfirmedSnapshot;
73
100
  };
101
+ /** Hydra node environment info reported in Greetings. */
102
+ export interface HydraEnv {
103
+ party: {
104
+ vkey: string;
105
+ };
106
+ signingKey?: string;
107
+ otherParties: {
108
+ vkey: string;
109
+ }[];
110
+ participants: string[];
111
+ contestationPeriod: number;
112
+ depositPeriod: number;
113
+ unsyncedPeriod?: number;
114
+ configuredPeers: string;
115
+ [key: string]: unknown;
116
+ }
117
+ /** Network connectivity info reported in Greetings. */
118
+ export interface HydraNetworkInfo {
119
+ networkConnected: boolean;
120
+ peersInfo: Record<string, unknown>;
121
+ [key: string]: unknown;
122
+ }
74
123
  /** Greetings message received on initial WebSocket connection. */
75
124
  export interface GreetingsMessage {
76
125
  tag: 'Greetings';
@@ -80,9 +129,29 @@ export interface GreetingsMessage {
80
129
  headStatus: HeadStatus;
81
130
  hydraHeadId?: string;
82
131
  snapshotUtxo?: HydraUTxOs;
83
- hydraNodeVersion?: string;
84
- env?: Record<string, unknown>;
85
- networkInfo?: Record<string, unknown>;
132
+ timestamp?: string;
133
+ hydraNodeVersion: string;
134
+ env: HydraEnv;
135
+ networkInfo: HydraNetworkInfo;
136
+ chainSyncedStatus: string;
137
+ currentSlot: number;
138
+ }
139
+ /**
140
+ * Summary of Hydra head info extracted from the Greetings message.
141
+ * Excludes the full UTxO snapshot to keep payloads small.
142
+ */
143
+ export interface HydraHeadInfo {
144
+ headStatus: HeadStatus;
145
+ headId: string | null;
146
+ nodeVersion: string | null;
147
+ me: string;
148
+ contestationPeriod: number | null;
149
+ depositPeriod: number | null;
150
+ participants: string[];
151
+ networkConnected: boolean;
152
+ peerCount: number;
153
+ chainSyncedStatus: string | null;
154
+ currentSlot: number | null;
86
155
  }
87
156
  export interface HeadIsInitializingMessage {
88
157
  tag: 'HeadIsInitializing';
@@ -90,6 +159,8 @@ export interface HeadIsInitializingMessage {
90
159
  parties: {
91
160
  vkey: string;
92
161
  }[];
162
+ seq: number;
163
+ timestamp: string;
93
164
  [key: string]: unknown;
94
165
  }
95
166
  export interface CommittedMessage {
@@ -98,78 +169,309 @@ export interface CommittedMessage {
98
169
  vkey: string;
99
170
  };
100
171
  utxo: HydraUTxOs;
172
+ seq: number;
173
+ timestamp: string;
101
174
  [key: string]: unknown;
102
175
  }
103
176
  export interface HeadIsOpenMessage {
104
177
  tag: 'HeadIsOpen';
178
+ headId: string;
105
179
  utxo: HydraUTxOs;
180
+ seq: number;
181
+ timestamp: string;
106
182
  [key: string]: unknown;
107
183
  }
108
184
  export interface HeadIsClosedMessage {
109
185
  tag: 'HeadIsClosed';
186
+ headId: string;
187
+ snapshotNumber: number;
188
+ contestationDeadline: string;
189
+ seq: number;
190
+ timestamp: string;
110
191
  [key: string]: unknown;
111
192
  }
112
193
  export interface HeadIsContestedMessage {
113
194
  tag: 'HeadIsContested';
195
+ headId: string;
196
+ snapshotNumber: number;
197
+ contestationDeadline: string;
198
+ seq: number;
199
+ timestamp: string;
114
200
  [key: string]: unknown;
115
201
  }
116
202
  export interface ReadyToFanoutMessage {
117
203
  tag: 'ReadyToFanout';
204
+ headId: string;
205
+ seq: number;
206
+ timestamp: string;
118
207
  [key: string]: unknown;
119
208
  }
120
209
  export interface HeadIsAbortedMessage {
121
210
  tag: 'HeadIsAborted';
211
+ headId: string;
212
+ utxo: HydraUTxOs;
213
+ seq: number;
214
+ timestamp: string;
122
215
  [key: string]: unknown;
123
216
  }
124
217
  export interface HeadIsFinalizedMessage {
125
218
  tag: 'HeadIsFinalized';
219
+ headId: string;
220
+ utxo: HydraUTxOs;
221
+ seq: number;
222
+ timestamp: string;
126
223
  [key: string]: unknown;
127
224
  }
128
225
  export interface TxValidMessage {
129
226
  tag: 'TxValid';
130
- transaction: HydraTransaction;
227
+ headId: string;
228
+ transactionId: string;
229
+ seq: number;
230
+ timestamp: string;
131
231
  [key: string]: unknown;
132
232
  }
133
233
  export interface TxInvalidMessage {
134
234
  tag: 'TxInvalid';
235
+ headId: string;
236
+ utxo: HydraUTxOs;
135
237
  transaction: HydraTransaction;
136
238
  validationError: {
137
239
  reason: string;
138
240
  };
241
+ seq: number;
242
+ timestamp: string;
139
243
  [key: string]: unknown;
140
244
  }
141
245
  export interface SnapshotConfirmedMessage {
142
246
  tag: 'SnapshotConfirmed';
247
+ headId: string;
248
+ snapshot: HydraSnapshot;
249
+ seq: number;
250
+ timestamp: string;
143
251
  [key: string]: unknown;
144
252
  }
145
- export interface DecommitApprovedMessage {
146
- tag: 'DecommitApproved';
253
+ export interface SnapshotSideLoadedMessage {
254
+ tag: 'SnapshotSideLoaded';
255
+ headId: string;
256
+ snapshotNumber: number;
257
+ seq: number;
258
+ timestamp: string;
147
259
  [key: string]: unknown;
148
260
  }
149
- export interface DecommitInvalidMessage {
150
- tag: 'DecommitInvalid';
151
- decommitInvalidReason: unknown;
261
+ export interface CommitRecordedMessage {
262
+ tag: 'CommitRecorded';
263
+ headId: string;
264
+ utxoToCommit: HydraUTxOs;
265
+ pendingDeposit: string;
266
+ deadline: string;
267
+ seq: number;
268
+ timestamp: string;
152
269
  [key: string]: unknown;
153
270
  }
154
- export interface DecommitFinalizedMessage {
155
- tag: 'DecommitFinalized';
271
+ export interface CommitApprovedMessage {
272
+ tag: 'CommitApproved';
273
+ headId: string;
274
+ utxoToCommit: HydraUTxOs;
275
+ seq: number;
276
+ timestamp: string;
156
277
  [key: string]: unknown;
157
278
  }
158
279
  export interface CommitFinalizedMessage {
159
280
  tag: 'CommitFinalized';
281
+ headId: string;
282
+ depositTxId: string;
283
+ seq: number;
284
+ timestamp: string;
160
285
  [key: string]: unknown;
161
286
  }
162
- export interface CommitApprovedMessage {
163
- tag: 'CommitApproved';
287
+ export interface CommitRecoveredMessage {
288
+ tag: 'CommitRecovered';
289
+ headId: string;
290
+ recoveredUTxO: HydraUTxOs;
291
+ recoveredTxId: string;
292
+ seq: number;
293
+ timestamp: string;
294
+ [key: string]: unknown;
295
+ }
296
+ export interface DepositActivatedMessage {
297
+ tag: 'DepositActivated';
298
+ headId: string;
299
+ depositTxId: string;
300
+ deadline: string;
301
+ chainTime: string;
302
+ seq: number;
303
+ timestamp: string;
304
+ [key: string]: unknown;
305
+ }
306
+ export interface DepositExpiredMessage {
307
+ tag: 'DepositExpired';
308
+ headId: string;
309
+ depositTxId: string;
310
+ deadline: string;
311
+ chainTime: string;
312
+ seq: number;
313
+ timestamp: string;
314
+ [key: string]: unknown;
315
+ }
316
+ export interface DecommitRequestedMessage {
317
+ tag: 'DecommitRequested';
318
+ headId: string;
319
+ decommitTx: HydraTransaction;
320
+ utxoToDecommit: HydraUTxOs;
321
+ seq: number;
322
+ timestamp: string;
323
+ [key: string]: unknown;
324
+ }
325
+ export interface DecommitApprovedMessage {
326
+ tag: 'DecommitApproved';
327
+ headId: string;
328
+ decommitTxId: string;
329
+ utxoToDecommit: HydraUTxOs;
330
+ seq: number;
331
+ timestamp: string;
332
+ [key: string]: unknown;
333
+ }
334
+ export interface DecommitFinalizedMessage {
335
+ tag: 'DecommitFinalized';
336
+ headId: string;
337
+ distributedUTxO: HydraUTxOs;
338
+ seq: number;
339
+ timestamp: string;
340
+ [key: string]: unknown;
341
+ }
342
+ export interface DecommitInvalidMessage {
343
+ tag: 'DecommitInvalid';
344
+ headId: string;
345
+ decommitTx: HydraTransaction;
346
+ decommitInvalidReason: {
347
+ tag: 'DecommitTxInvalid';
348
+ localUTxO: HydraUTxOs;
349
+ validationError: {
350
+ reason: string;
351
+ };
352
+ } | {
353
+ tag: 'DecommitAlreadyInFlight';
354
+ otherDecommitTxId: string;
355
+ };
356
+ seq: number;
357
+ timestamp: string;
164
358
  [key: string]: unknown;
165
359
  }
166
360
  export interface CommandFailedMessage {
167
361
  tag: 'CommandFailed';
168
362
  clientInput: ClientInput;
363
+ state: unknown;
169
364
  [key: string]: unknown;
170
365
  }
171
366
  export interface PostTxOnChainFailedMessage {
172
367
  tag: 'PostTxOnChainFailed';
368
+ postChainTx: unknown;
369
+ postTxError: unknown;
370
+ [key: string]: unknown;
371
+ }
372
+ export interface InvalidInputMessage {
373
+ tag: 'InvalidInput';
374
+ reason: string;
375
+ input: string;
376
+ [key: string]: unknown;
377
+ }
378
+ export interface RejectedInputBecauseUnsyncedMessage {
379
+ tag: 'RejectedInputBecauseUnsynced';
380
+ clientInput: ClientInput;
381
+ drift: number;
382
+ [key: string]: unknown;
383
+ }
384
+ export interface SideLoadSnapshotRejectedMessage {
385
+ tag: 'SideLoadSnapshotRejected';
386
+ clientInput: ClientInput;
387
+ requirementFailure: unknown;
388
+ [key: string]: unknown;
389
+ }
390
+ export interface PeerConnectedMessage {
391
+ tag: 'PeerConnected';
392
+ peer: string;
393
+ seq: number;
394
+ timestamp: string;
395
+ [key: string]: unknown;
396
+ }
397
+ export interface PeerDisconnectedMessage {
398
+ tag: 'PeerDisconnected';
399
+ peer: string;
400
+ seq: number;
401
+ timestamp: string;
402
+ [key: string]: unknown;
403
+ }
404
+ export interface NetworkConnectedMessage {
405
+ tag: 'NetworkConnected';
406
+ seq: number;
407
+ timestamp: string;
408
+ [key: string]: unknown;
409
+ }
410
+ export interface NetworkDisconnectedMessage {
411
+ tag: 'NetworkDisconnected';
412
+ seq: number;
413
+ timestamp: string;
414
+ [key: string]: unknown;
415
+ }
416
+ export interface NetworkVersionMismatchMessage {
417
+ tag: 'NetworkVersionMismatch';
418
+ ourVersion: unknown;
419
+ theirVersion: unknown;
420
+ seq: number;
421
+ timestamp: string;
422
+ [key: string]: unknown;
423
+ }
424
+ export interface NetworkClusterIDMismatchMessage {
425
+ tag: 'NetworkClusterIDMismatch';
426
+ clusterPeers?: unknown;
427
+ misconfiguredPeers?: unknown;
428
+ seq: number;
429
+ timestamp: string;
430
+ [key: string]: unknown;
431
+ }
432
+ export interface SyncedStatusReportMessage {
433
+ tag: 'SyncedStatusReport';
434
+ chainSlot: number;
435
+ chainTime: string;
436
+ drift: number;
437
+ synced: string;
438
+ [key: string]: unknown;
439
+ }
440
+ export interface NodeSyncedMessage {
441
+ tag: 'NodeSynced';
442
+ chainSlot: number;
443
+ chainTime: string;
444
+ drift: number;
445
+ seq: number;
446
+ timestamp: string;
447
+ [key: string]: unknown;
448
+ }
449
+ export interface NodeUnsyncedMessage {
450
+ tag: 'NodeUnsynced';
451
+ chainSlot: number;
452
+ chainTime: string;
453
+ drift: number;
454
+ seq: number;
455
+ timestamp: string;
456
+ [key: string]: unknown;
457
+ }
458
+ export interface IgnoredHeadInitializingMessage {
459
+ tag: 'IgnoredHeadInitializing';
460
+ headId: string;
461
+ contestationPeriod: number;
462
+ parties: {
463
+ vkey: string;
464
+ }[];
465
+ participants: string[];
466
+ seq: number;
467
+ timestamp: string;
468
+ [key: string]: unknown;
469
+ }
470
+ export interface EventLogRotatedMessage {
471
+ tag: 'EventLogRotated';
472
+ seq: number;
473
+ checkpoint: unknown;
474
+ timestamp: string;
173
475
  [key: string]: unknown;
174
476
  }
175
477
  /** Catch-all for message types not explicitly defined above. */
@@ -178,7 +480,7 @@ export interface UnknownMessage {
178
480
  [key: string]: unknown;
179
481
  }
180
482
  /** All possible messages the Hydra node can send over its WebSocket API. */
181
- export type ServerOutput = GreetingsMessage | HeadIsInitializingMessage | CommittedMessage | HeadIsOpenMessage | HeadIsClosedMessage | HeadIsContestedMessage | ReadyToFanoutMessage | HeadIsAbortedMessage | HeadIsFinalizedMessage | TxValidMessage | TxInvalidMessage | SnapshotConfirmedMessage | DecommitApprovedMessage | DecommitInvalidMessage | DecommitFinalizedMessage | CommitFinalizedMessage | CommitApprovedMessage | CommandFailedMessage | PostTxOnChainFailedMessage | UnknownMessage;
483
+ export type ServerOutput = GreetingsMessage | HeadIsInitializingMessage | CommittedMessage | HeadIsOpenMessage | HeadIsClosedMessage | HeadIsContestedMessage | ReadyToFanoutMessage | HeadIsAbortedMessage | HeadIsFinalizedMessage | TxValidMessage | TxInvalidMessage | SnapshotConfirmedMessage | SnapshotSideLoadedMessage | CommitRecordedMessage | CommitApprovedMessage | CommitFinalizedMessage | CommitRecoveredMessage | DepositActivatedMessage | DepositExpiredMessage | DecommitRequestedMessage | DecommitApprovedMessage | DecommitFinalizedMessage | DecommitInvalidMessage | CommandFailedMessage | PostTxOnChainFailedMessage | InvalidInputMessage | RejectedInputBecauseUnsyncedMessage | SideLoadSnapshotRejectedMessage | PeerConnectedMessage | PeerDisconnectedMessage | NetworkConnectedMessage | NetworkDisconnectedMessage | NetworkVersionMismatchMessage | NetworkClusterIDMismatchMessage | SyncedStatusReportMessage | NodeSyncedMessage | NodeUnsyncedMessage | IgnoredHeadInitializingMessage | EventLogRotatedMessage | UnknownMessage;
182
484
  /** Client echo messages (errors, command failures). */
183
485
  export type ClientMessage = CommandFailedMessage | PostTxOnChainFailedMessage;
184
486
  /** Any message received via the Hydra WebSocket. */
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export type { DiskCache, DiskCacheConfig } from './cache/disk-cache.js';
2
2
  export { createDiskCache } from './cache/disk-cache.js';
3
3
  export { optionalEnv, requireEnv } from './config.js';
4
4
  export { HydraMonitor } from './hydra/hydra-monitor.js';
5
- export type { HeadStatus, HydraMessage, HydraMonitorOptions, HydraStatus, HydraTransaction, HydraWsMessage, hydraStatus, hydraTransaction, ServerOutput, TimestampedEvent, } from './hydra/messages.js';
5
+ export type { ConfirmedSnapshot, HeadStatus, HydraHeadInfo, HydraMessage, HydraMonitorOptions, HydraSnapshot, HydraStatus, HydraTransaction, HydraWsMessage, hydraStatus, hydraTransaction, ServerOutput, TimestampedEvent, } from './hydra/messages.js';
6
6
  export type { ParsedUtxo, UtxoQueryOptions } from './hydra/utxo.js';
7
7
  export { getUtxoSet, queryUtxoByAddress } from './hydra/utxo.js';
8
8
  export type { IpfsClient, IpfsConfig, PinResult } from './ipfs/ipfs.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lerna-labs/hydra-sdk",
3
- "version": "1.0.0-beta.21",
3
+ "version": "1.0.0-beta.23",
4
4
  "description": "TypeScript SDK for managing Cardano Hydra Heads — lifecycle, UTxO queries, wallet management, transaction submission, and signature verification",
5
5
  "keywords": [
6
6
  "cardano",