@lerna-labs/hydra-sdk 1.0.0-beta.16 → 1.0.0-beta.18

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.
@@ -0,0 +1,28 @@
1
+ import type { CommitBlueprintPayload, HydraTransaction, HydraUTxOEntry, HydraUTxOs } from './types.js';
2
+ /**
3
+ * HTTP client for the Hydra node REST API.
4
+ *
5
+ * Uses native `fetch` (Node 18+). Accepts 200 and 202 as success responses.
6
+ */
7
+ export declare class HydraHttpClient {
8
+ private readonly baseUrl;
9
+ constructor(baseUrl: string);
10
+ /**
11
+ * Build a commit transaction.
12
+ *
13
+ * `POST /commit` — returns the unsigned L1 transaction CBOR hex.
14
+ */
15
+ buildCommit(payload: HydraUTxOs | CommitBlueprintPayload | Record<string, never>): Promise<string>;
16
+ /**
17
+ * Publish a decommit transaction.
18
+ *
19
+ * `POST /decommit` — submits the decommit request to the Hydra node.
20
+ */
21
+ publishDecommit(transaction: HydraTransaction): Promise<unknown>;
22
+ /** Fetch the current UTxO snapshot. `GET /snapshot/utxo` */
23
+ getSnapshotUtxo(): Promise<Record<string, HydraUTxOEntry>>;
24
+ /** Fetch protocol parameters. `GET /protocol-parameters` */
25
+ getProtocolParameters(): Promise<unknown>;
26
+ private post;
27
+ private get;
28
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * HTTP client for the Hydra node REST API.
3
+ *
4
+ * Uses native `fetch` (Node 18+). Accepts 200 and 202 as success responses.
5
+ */
6
+ export class HydraHttpClient {
7
+ baseUrl;
8
+ constructor(baseUrl) {
9
+ this.baseUrl = baseUrl.replace(/\/+$/, '');
10
+ }
11
+ /**
12
+ * Build a commit transaction.
13
+ *
14
+ * `POST /commit` — returns the unsigned L1 transaction CBOR hex.
15
+ */
16
+ async buildCommit(payload) {
17
+ const response = await this.post('/commit', payload);
18
+ return response.cborHex;
19
+ }
20
+ /**
21
+ * Publish a decommit transaction.
22
+ *
23
+ * `POST /decommit` — submits the decommit request to the Hydra node.
24
+ */
25
+ async publishDecommit(transaction) {
26
+ return this.post('/decommit', { tag: 'Decommit', transaction });
27
+ }
28
+ /** Fetch the current UTxO snapshot. `GET /snapshot/utxo` */
29
+ async getSnapshotUtxo() {
30
+ return this.get('/snapshot/utxo');
31
+ }
32
+ /** Fetch protocol parameters. `GET /protocol-parameters` */
33
+ async getProtocolParameters() {
34
+ return this.get('/protocol-parameters');
35
+ }
36
+ async post(path, payload) {
37
+ const response = await fetch(`${this.baseUrl}${path}`, {
38
+ method: 'POST',
39
+ headers: { 'Content-Type': 'application/json' },
40
+ body: JSON.stringify(payload),
41
+ });
42
+ if (!response.ok && response.status !== 202) {
43
+ const body = await response.text().catch(() => '');
44
+ throw new Error(`Hydra HTTP ${response.status} on POST ${path}: ${body}`);
45
+ }
46
+ return response.json();
47
+ }
48
+ async get(path) {
49
+ const response = await fetch(`${this.baseUrl}${path}`);
50
+ if (!response.ok && response.status !== 202) {
51
+ const body = await response.text().catch(() => '');
52
+ throw new Error(`Hydra HTTP ${response.status} on GET ${path}: ${body}`);
53
+ }
54
+ return response.json();
55
+ }
56
+ }
@@ -0,0 +1,41 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { ClientInput, ConnectionState, HydraStatus } from './types.js';
3
+ /**
4
+ * Thin WebSocket wrapper for the Hydra node.
5
+ *
6
+ * Uses `EventEmitter` for multi-listener message dispatch (no single-callback
7
+ * overwrite). Emits:
8
+ *
9
+ * - `'message'` — `(msg: HydraWsMessage)` for every incoming message
10
+ * - `'status'` — `(status: HydraStatus)` on head-status changes
11
+ * - `'error'` — `(err: Error)`
12
+ * - `'close'` — `()`
13
+ */
14
+ export declare class HydraWebSocket extends EventEmitter {
15
+ private ws;
16
+ private readonly url;
17
+ private _status;
18
+ private _connectionState;
19
+ constructor(wsUrl: string);
20
+ /** Current connection state. */
21
+ get connectionState(): ConnectionState;
22
+ /** Open the WebSocket connection. Resolves when the socket is open. */
23
+ connect(): Promise<void>;
24
+ /**
25
+ * Connect and wait for the Greetings message from the Hydra node.
26
+ *
27
+ * Unlike `HydraProvider.isConnected()`, this does NOT overwrite existing
28
+ * message handlers — it uses a one-time EventEmitter listener.
29
+ */
30
+ waitForGreetings(timeoutMs?: number): Promise<boolean>;
31
+ /** Close the WebSocket. */
32
+ disconnect(timeoutMs?: number): Promise<void>;
33
+ /** Send a ClientInput message as JSON over the WebSocket. */
34
+ send(message: ClientInput): void;
35
+ /** Current Hydra head status derived from messages. */
36
+ getStatus(): HydraStatus;
37
+ /** Register a status-change listener. Returns current status. */
38
+ onStatusChange(callback: (status: HydraStatus) => void): HydraStatus;
39
+ private handleMessage;
40
+ private updateStatus;
41
+ }
@@ -0,0 +1,159 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import WebSocket from 'ws';
3
+ const HEAD_STATUS_TO_HYDRA = {
4
+ Idle: 'IDLE',
5
+ Initializing: 'INITIALIZING',
6
+ Open: 'OPEN',
7
+ Closed: 'CLOSED',
8
+ FanoutPossible: 'FANOUT_POSSIBLE',
9
+ Final: 'FINAL',
10
+ };
11
+ const TAG_TO_HYDRA = {
12
+ HeadIsInitializing: 'INITIALIZING',
13
+ HeadIsOpen: 'OPEN',
14
+ HeadIsClosed: 'CLOSED',
15
+ ReadyToFanout: 'FANOUT_POSSIBLE',
16
+ HeadIsFinalized: 'FINAL',
17
+ };
18
+ /**
19
+ * Thin WebSocket wrapper for the Hydra node.
20
+ *
21
+ * Uses `EventEmitter` for multi-listener message dispatch (no single-callback
22
+ * overwrite). Emits:
23
+ *
24
+ * - `'message'` — `(msg: HydraWsMessage)` for every incoming message
25
+ * - `'status'` — `(status: HydraStatus)` on head-status changes
26
+ * - `'error'` — `(err: Error)`
27
+ * - `'close'` — `()`
28
+ */
29
+ export class HydraWebSocket extends EventEmitter {
30
+ ws = null;
31
+ url;
32
+ _status = 'IDLE';
33
+ _connectionState = 'IDLE';
34
+ constructor(wsUrl) {
35
+ super();
36
+ this.url = wsUrl;
37
+ }
38
+ /** Current connection state. */
39
+ get connectionState() {
40
+ return this._connectionState;
41
+ }
42
+ /** Open the WebSocket connection. Resolves when the socket is open. */
43
+ async connect() {
44
+ if (this.ws?.readyState === WebSocket.OPEN)
45
+ return;
46
+ return new Promise((resolve, reject) => {
47
+ const ws = new WebSocket(this.url);
48
+ ws.on('open', () => {
49
+ this.ws = ws;
50
+ this._connectionState = 'CONNECTING';
51
+ resolve();
52
+ });
53
+ ws.on('message', (data) => {
54
+ try {
55
+ const msg = JSON.parse(data.toString());
56
+ this.handleMessage(msg);
57
+ }
58
+ catch {
59
+ // Ignore non-JSON messages
60
+ }
61
+ });
62
+ ws.on('error', (err) => {
63
+ this._connectionState = 'FAILED';
64
+ this.emit('error', err);
65
+ reject(new Error(`WebSocket error: ${err.message}`));
66
+ });
67
+ ws.on('close', () => {
68
+ this._connectionState = 'DISCONNECTED';
69
+ this.ws = null;
70
+ this.emit('close');
71
+ });
72
+ });
73
+ }
74
+ /**
75
+ * Connect and wait for the Greetings message from the Hydra node.
76
+ *
77
+ * Unlike `HydraProvider.isConnected()`, this does NOT overwrite existing
78
+ * message handlers — it uses a one-time EventEmitter listener.
79
+ */
80
+ async waitForGreetings(timeoutMs = 30_000) {
81
+ if (this._connectionState === 'CONNECTED')
82
+ return true;
83
+ await this.connect();
84
+ return new Promise((resolve, reject) => {
85
+ const timer = setTimeout(() => {
86
+ this.removeListener('message', onMsg);
87
+ this._connectionState = 'FAILED';
88
+ reject(new Error('Connection timed out: no Greetings from Hydra node'));
89
+ }, timeoutMs);
90
+ const onMsg = (msg) => {
91
+ if (msg.tag === 'Greetings') {
92
+ clearTimeout(timer);
93
+ this.removeListener('message', onMsg);
94
+ this._connectionState = 'CONNECTED';
95
+ resolve(true);
96
+ }
97
+ };
98
+ this.on('message', onMsg);
99
+ });
100
+ }
101
+ /** Close the WebSocket. */
102
+ async disconnect(timeoutMs = 5000) {
103
+ if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
104
+ this._connectionState = 'DISCONNECTED';
105
+ return;
106
+ }
107
+ return new Promise((resolve) => {
108
+ const timer = setTimeout(() => {
109
+ this.ws?.terminate();
110
+ this._connectionState = 'DISCONNECTED';
111
+ this.ws = null;
112
+ resolve();
113
+ }, timeoutMs);
114
+ this.ws.on('close', () => {
115
+ clearTimeout(timer);
116
+ this._connectionState = 'DISCONNECTED';
117
+ this.ws = null;
118
+ resolve();
119
+ });
120
+ this.ws.close();
121
+ });
122
+ }
123
+ /** Send a ClientInput message as JSON over the WebSocket. */
124
+ send(message) {
125
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
126
+ throw new Error('WebSocket is not connected');
127
+ }
128
+ this.ws.send(JSON.stringify(message));
129
+ }
130
+ /** Current Hydra head status derived from messages. */
131
+ getStatus() {
132
+ return this._status;
133
+ }
134
+ /** Register a status-change listener. Returns current status. */
135
+ onStatusChange(callback) {
136
+ this.on('status', callback);
137
+ return this._status;
138
+ }
139
+ handleMessage(msg) {
140
+ this.emit('message', msg);
141
+ // Update status from Greetings headStatus
142
+ if (msg.tag === 'Greetings' && 'headStatus' in msg) {
143
+ const mapped = HEAD_STATUS_TO_HYDRA[msg.headStatus];
144
+ if (mapped)
145
+ this.updateStatus(mapped);
146
+ return;
147
+ }
148
+ // Update status from state transition messages
149
+ const mapped = TAG_TO_HYDRA[msg.tag];
150
+ if (mapped)
151
+ this.updateStatus(mapped);
152
+ }
153
+ updateStatus(newStatus) {
154
+ if (this._status !== newStatus) {
155
+ this._status = newStatus;
156
+ this.emit('status', newStatus);
157
+ }
158
+ }
159
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Re-exported Hydra WebSocket message types from `@meshsdk/hydra`.
2
+ * Re-exported Hydra WebSocket message types.
3
3
  *
4
4
  * `ServerOutput` is a discriminated union (on `.tag`) of all possible messages
5
5
  * the Hydra node can send over its WebSocket API. Use `Extract` to narrow:
@@ -7,25 +7,8 @@
7
7
  * @example
8
8
  * ```ts
9
9
  * function handleOpen(msg: HydraMessage<"HeadIsOpen">) {
10
- * console.log(msg.headId, msg.utxo);
10
+ * console.log(msg.tag);
11
11
  * }
12
12
  * ```
13
13
  */
14
- export type { ClientInput, ClientMessage, ConnectionState, ServerOutput } from '@meshsdk/hydra';
15
- import type { ClientMessage, ServerOutput } from '@meshsdk/hydra';
16
- /** Any message received via the Hydra WebSocket (server output or client echo). */
17
- export type HydraWsMessage = ServerOutput | ClientMessage;
18
- /**
19
- * Extract a specific message type from the `ServerOutput` union by its `tag`.
20
- *
21
- * @example
22
- * ```ts
23
- * type Greetings = HydraMessage<"Greetings">;
24
- * // { tag: "Greetings"; me: { vkey: string }; headStatus: HeadStatus; ... }
25
- * ```
26
- */
27
- export type HydraMessage<T extends ServerOutput['tag']> = Extract<ServerOutput, {
28
- tag: T;
29
- }>;
30
- /** Possible Hydra head states as reported in the `Greetings` message. */
31
- export type HeadStatus = 'Idle' | 'Initializing' | 'Open' | 'Closed' | 'FanoutPossible' | 'Final';
14
+ export type { ClientInput, ClientMessage, ConnectionState, HeadStatus, HydraMessage, HydraStatus, HydraTransaction, HydraWsMessage, hydraStatus, hydraTransaction, ServerOutput, } from './types.js';
@@ -0,0 +1,196 @@
1
+ /** A Cardano transaction in Hydra's wire format. */
2
+ export type HydraTransaction = {
3
+ type: 'Tx ConwayEra' | 'Unwitnessed Tx ConwayEra' | 'Witnessed Tx ConwayEra';
4
+ description: string;
5
+ cborHex: string;
6
+ txId?: string;
7
+ };
8
+ /** @deprecated Use HydraTransaction */
9
+ export type hydraTransaction = HydraTransaction;
10
+ /** Hydra's nested asset value format: `{ lovelace: N, policyId: { assetNameHex: N } }`. */
11
+ export type HydraAssets = {
12
+ lovelace: number;
13
+ } & {
14
+ [policyId: string]: number | {
15
+ [assetNameHex: string]: number;
16
+ };
17
+ };
18
+ export interface HydraReferenceScript {
19
+ script: {
20
+ cborHex: string;
21
+ description: string;
22
+ type: string | null;
23
+ };
24
+ scriptLanguage: string;
25
+ }
26
+ /** A single UTxO entry in Hydra's wire format. */
27
+ export interface HydraUTxOEntry {
28
+ address: string;
29
+ datum: string | null;
30
+ inlineDatum: object | null;
31
+ inlineDatumRaw: string | null;
32
+ inlineDatumhash: string | null;
33
+ referenceScript: HydraReferenceScript | null;
34
+ value: HydraAssets;
35
+ }
36
+ /** A set of UTxOs keyed by `"txHash#outputIndex"`. */
37
+ export type HydraUTxOs = {
38
+ [txRef: string]: HydraUTxOEntry;
39
+ };
40
+ /** Payload for blueprint-based commits. */
41
+ export interface CommitBlueprintPayload {
42
+ blueprintTx: HydraTransaction;
43
+ utxo: HydraUTxOs;
44
+ }
45
+ /** Possible Hydra head states as reported in the `Greetings` message (mixed-case). */
46
+ export type HeadStatus = 'Idle' | 'Initializing' | 'Open' | 'Closed' | 'FanoutPossible' | 'Final';
47
+ /** Hydra status values (uppercase, as used by HydraProvider status tracking). */
48
+ export type HydraStatus = 'IDLE' | 'INITIALIZING' | 'OPEN' | 'CLOSED' | 'FANOUT_POSSIBLE' | 'FINAL';
49
+ /** @deprecated Use HydraStatus */
50
+ export type hydraStatus = HydraStatus;
51
+ /** Connection state of the WebSocket. */
52
+ export type ConnectionState = 'IDLE' | 'CONNECTING' | 'CONNECTED' | 'FAILED' | 'DISCONNECTED';
53
+ /** Messages that can be sent to the Hydra node over WebSocket. */
54
+ export type ClientInput = {
55
+ tag: 'Init';
56
+ } | {
57
+ tag: 'Abort';
58
+ } | {
59
+ tag: 'NewTx';
60
+ transaction: HydraTransaction;
61
+ } | {
62
+ tag: 'Close';
63
+ } | {
64
+ tag: 'Contest';
65
+ } | {
66
+ tag: 'Fanout';
67
+ } | {
68
+ tag: 'Decommit';
69
+ transaction: HydraTransaction;
70
+ } | {
71
+ tag: 'Recover';
72
+ recoverTxId: string;
73
+ };
74
+ /** Greetings message received on initial WebSocket connection. */
75
+ export interface GreetingsMessage {
76
+ tag: 'Greetings';
77
+ me: {
78
+ vkey: string;
79
+ };
80
+ headStatus: HeadStatus;
81
+ hydraHeadId?: string;
82
+ snapshotUtxo?: HydraUTxOs;
83
+ hydraNodeVersion?: string;
84
+ env?: Record<string, unknown>;
85
+ networkInfo?: Record<string, unknown>;
86
+ }
87
+ export interface HeadIsInitializingMessage {
88
+ tag: 'HeadIsInitializing';
89
+ headId: string;
90
+ parties: {
91
+ vkey: string;
92
+ }[];
93
+ [key: string]: unknown;
94
+ }
95
+ export interface CommittedMessage {
96
+ tag: 'Committed';
97
+ party: {
98
+ vkey: string;
99
+ };
100
+ utxo: HydraUTxOs;
101
+ [key: string]: unknown;
102
+ }
103
+ export interface HeadIsOpenMessage {
104
+ tag: 'HeadIsOpen';
105
+ utxo: HydraUTxOs;
106
+ [key: string]: unknown;
107
+ }
108
+ export interface HeadIsClosedMessage {
109
+ tag: 'HeadIsClosed';
110
+ [key: string]: unknown;
111
+ }
112
+ export interface HeadIsContestedMessage {
113
+ tag: 'HeadIsContested';
114
+ [key: string]: unknown;
115
+ }
116
+ export interface ReadyToFanoutMessage {
117
+ tag: 'ReadyToFanout';
118
+ [key: string]: unknown;
119
+ }
120
+ export interface HeadIsAbortedMessage {
121
+ tag: 'HeadIsAborted';
122
+ [key: string]: unknown;
123
+ }
124
+ export interface HeadIsFinalizedMessage {
125
+ tag: 'HeadIsFinalized';
126
+ [key: string]: unknown;
127
+ }
128
+ export interface TxValidMessage {
129
+ tag: 'TxValid';
130
+ transaction: HydraTransaction;
131
+ [key: string]: unknown;
132
+ }
133
+ export interface TxInvalidMessage {
134
+ tag: 'TxInvalid';
135
+ transaction: HydraTransaction;
136
+ validationError: {
137
+ reason: string;
138
+ };
139
+ [key: string]: unknown;
140
+ }
141
+ export interface SnapshotConfirmedMessage {
142
+ tag: 'SnapshotConfirmed';
143
+ [key: string]: unknown;
144
+ }
145
+ export interface DecommitApprovedMessage {
146
+ tag: 'DecommitApproved';
147
+ [key: string]: unknown;
148
+ }
149
+ export interface DecommitInvalidMessage {
150
+ tag: 'DecommitInvalid';
151
+ decommitInvalidReason: unknown;
152
+ [key: string]: unknown;
153
+ }
154
+ export interface DecommitFinalizedMessage {
155
+ tag: 'DecommitFinalized';
156
+ [key: string]: unknown;
157
+ }
158
+ export interface CommitFinalizedMessage {
159
+ tag: 'CommitFinalized';
160
+ [key: string]: unknown;
161
+ }
162
+ export interface CommitApprovedMessage {
163
+ tag: 'CommitApproved';
164
+ [key: string]: unknown;
165
+ }
166
+ export interface CommandFailedMessage {
167
+ tag: 'CommandFailed';
168
+ clientInput: ClientInput;
169
+ [key: string]: unknown;
170
+ }
171
+ export interface PostTxOnChainFailedMessage {
172
+ tag: 'PostTxOnChainFailed';
173
+ [key: string]: unknown;
174
+ }
175
+ /** Catch-all for message types not explicitly defined above. */
176
+ export interface UnknownMessage {
177
+ tag: string;
178
+ [key: string]: unknown;
179
+ }
180
+ /** 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;
182
+ /** Client echo messages (errors, command failures). */
183
+ export type ClientMessage = CommandFailedMessage | PostTxOnChainFailedMessage;
184
+ /** Any message received via the Hydra WebSocket. */
185
+ export type HydraWsMessage = ServerOutput | ClientMessage;
186
+ /**
187
+ * Extract a specific message type from the `ServerOutput` union by its `tag`.
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * type Greetings = HydraMessage<"Greetings">;
192
+ * ```
193
+ */
194
+ export type HydraMessage<T extends ServerOutput['tag']> = Extract<ServerOutput, {
195
+ tag: T;
196
+ }>;
@@ -0,0 +1,2 @@
1
+ // ── Hydra Transaction ────────────────────────────────────────────────
2
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { Asset, UTxO } from '@meshsdk/common';
2
+ import type { HydraAssets, HydraUTxOEntry, HydraUTxOs } from './types.js';
3
+ /** Convert MeshSDK `Asset[]` to Hydra's nested value format. */
4
+ export declare function toHydraAssets(assets: Asset[]): HydraAssets;
5
+ /** Convert Hydra's nested value format back to MeshSDK `Asset[]`. */
6
+ export declare function fromHydraAssets(assetsObj: HydraAssets): Asset[];
7
+ /** Convert a single MeshSDK UTxO to Hydra wire format. */
8
+ export declare function toHydraUTxO(utxo: UTxO): HydraUTxOEntry;
9
+ /** Convert multiple MeshSDK UTxOs to Hydra wire format (keyed by `"txHash#outputIndex"`). */
10
+ export declare function toHydraUTxOs(utxos: UTxO[]): HydraUTxOs;
@@ -0,0 +1,111 @@
1
+ import { fromScriptRef, parseDatumCbor } from '@meshsdk/core-cst';
2
+ // ── Asset Conversion ─────────────────────────────────────────────────
3
+ /** Convert MeshSDK `Asset[]` to Hydra's nested value format. */
4
+ export function toHydraAssets(assets) {
5
+ return assets.reduce((acc, asset) => {
6
+ if (asset.unit === '' || asset.unit === 'lovelace') {
7
+ acc.lovelace += Number(asset.quantity);
8
+ }
9
+ else {
10
+ const policyId = asset.unit.slice(0, 56);
11
+ const assetNameHex = asset.unit.slice(56) || '';
12
+ if (!acc[policyId] || typeof acc[policyId] === 'number') {
13
+ acc[policyId] = {};
14
+ }
15
+ const policy = acc[policyId];
16
+ policy[assetNameHex] = (policy[assetNameHex] ?? 0) + Number(asset.quantity);
17
+ }
18
+ return acc;
19
+ }, { lovelace: 0 });
20
+ }
21
+ /** Convert Hydra's nested value format back to MeshSDK `Asset[]`. */
22
+ export function fromHydraAssets(assetsObj) {
23
+ const result = [];
24
+ if (assetsObj.lovelace && assetsObj.lovelace > 0) {
25
+ result.push({ unit: 'lovelace', quantity: String(assetsObj.lovelace) });
26
+ }
27
+ for (const [policyId, assets] of Object.entries(assetsObj)) {
28
+ if (policyId === 'lovelace')
29
+ continue;
30
+ if (typeof assets !== 'object')
31
+ continue;
32
+ for (const [assetNameHex, quantity] of Object.entries(assets)) {
33
+ result.push({ unit: policyId + assetNameHex, quantity: String(quantity) });
34
+ }
35
+ }
36
+ return result;
37
+ }
38
+ // ── Reference Script Conversion ──────────────────────────────────────
39
+ function resolveReferenceScript(scriptRef) {
40
+ if (!scriptRef)
41
+ return null;
42
+ const scriptInstance = fromScriptRef(scriptRef);
43
+ if (!scriptInstance)
44
+ return null;
45
+ let scriptType = 'Unknown';
46
+ let scriptLanguage = null;
47
+ if ('code' in scriptInstance) {
48
+ switch (scriptInstance.version) {
49
+ case 'V1':
50
+ scriptType = 'PlutusScriptV1';
51
+ scriptLanguage = 'PlutusScriptLanguage PlutusScriptV1';
52
+ break;
53
+ case 'V2':
54
+ scriptType = 'PlutusScriptV2';
55
+ scriptLanguage = 'PlutusScriptLanguage PlutusScriptV2';
56
+ break;
57
+ case 'V3':
58
+ scriptType = 'PlutusScriptV3';
59
+ scriptLanguage = 'PlutusScriptLanguage PlutusScriptV3';
60
+ break;
61
+ }
62
+ }
63
+ else {
64
+ scriptType = 'SimpleScript';
65
+ scriptLanguage = 'NativeScriptLanguage SimpleScript';
66
+ }
67
+ if (!scriptLanguage || scriptType === 'Unknown')
68
+ return null;
69
+ return {
70
+ script: {
71
+ cborHex: scriptRef,
72
+ description: '',
73
+ type: scriptType,
74
+ },
75
+ scriptLanguage,
76
+ };
77
+ }
78
+ // ── Datum Resolution ─────────────────────────────────────────────────
79
+ function resolvePlutusData(datumCbor) {
80
+ const data = parseDatumCbor(datumCbor);
81
+ function normalize(value) {
82
+ if (typeof value === 'bigint') {
83
+ return value <= Number.MAX_SAFE_INTEGER && value >= Number.MIN_SAFE_INTEGER ? Number(value) : value.toString();
84
+ }
85
+ if (Array.isArray(value)) {
86
+ return value.map(normalize);
87
+ }
88
+ if (value && typeof value === 'object') {
89
+ return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, normalize(v)]));
90
+ }
91
+ return value;
92
+ }
93
+ return { inlineDatum: normalize(data) };
94
+ }
95
+ // ── UTxO Conversion ──────────────────────────────────────────────────
96
+ /** Convert a single MeshSDK UTxO to Hydra wire format. */
97
+ export function toHydraUTxO(utxo) {
98
+ return {
99
+ address: utxo.output.address,
100
+ datum: null,
101
+ inlineDatum: utxo.output.plutusData ? resolvePlutusData(utxo.output.plutusData).inlineDatum : null,
102
+ inlineDatumRaw: utxo.output.plutusData ?? null,
103
+ inlineDatumhash: utxo.output.dataHash ?? null,
104
+ referenceScript: utxo.output.scriptRef ? resolveReferenceScript(utxo.output.scriptRef) : null,
105
+ value: toHydraAssets(utxo.output.amount),
106
+ };
107
+ }
108
+ /** Convert multiple MeshSDK UTxOs to Hydra wire format (keyed by `"txHash#outputIndex"`). */
109
+ export function toHydraUTxOs(utxos) {
110
+ return Object.fromEntries(utxos.map((utxo) => [`${utxo.input.txHash}#${utxo.input.outputIndex}`, toHydraUTxO(utxo)]));
111
+ }
package/dist/index.d.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  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
- export type { HeadStatus, HydraMessage, HydraWsMessage, ServerOutput } from './hydra/messages.js';
4
+ export type { HeadStatus, HydraMessage, HydraStatus, HydraTransaction, HydraWsMessage, hydraStatus, hydraTransaction, ServerOutput, } from './hydra/messages.js';
5
5
  export type { ParsedUtxo } from './hydra/utxo.js';
6
6
  export { getUtxoSet, queryUtxoByAddress } from './hydra/utxo.js';
7
7
  export type { IpfsClient, IpfsConfig, PinResult } from './ipfs/ipfs.js';
8
8
  export { createIpfsClient } from './ipfs/ipfs.js';
9
9
  export { getAdmin } from './mesh/get-admin.js';
10
10
  export { createMultisigAddress, createNativeScript } from './mesh/native-script.js';
11
- export { CommitArgs, UTxORef, Wrangler } from './mesh/wrangler.js';
12
11
  export { submitTx } from './tx3/submit-tx.js';
13
12
  export { chunkString } from './utils/chunk-string.js';
14
13
  export { bufferToAscii, bufferToHex, verifySignature } from './utils/verify-signature.js';
14
+ export { CommitArgs, UTxORef, Wrangler } from './wrangler.js';
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ export { getUtxoSet, queryUtxoByAddress } from './hydra/utxo.js';
4
4
  export { createIpfsClient } from './ipfs/ipfs.js';
5
5
  export { getAdmin } from './mesh/get-admin.js';
6
6
  export { createMultisigAddress, createNativeScript } from './mesh/native-script.js';
7
- export { Wrangler } from './mesh/wrangler.js';
8
7
  export { submitTx } from './tx3/submit-tx.js';
9
8
  export { chunkString } from './utils/chunk-string.js';
10
9
  export { bufferToAscii, bufferToHex, verifySignature } from './utils/verify-signature.js';
10
+ export { Wrangler } from './wrangler.js';
package/dist/test.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as dotenv from 'dotenv';
2
2
  dotenv.config({ path: '.local.env' });
3
3
  import { BlockfrostProvider, MeshTxBuilder, MeshWallet } from '@meshsdk/core';
4
- import { Wrangler } from './mesh/wrangler';
4
+ import { Wrangler } from './wrangler.js';
5
5
  (async () => {
6
6
  const admin_wallet = new MeshWallet({
7
7
  networkId: parseInt(process.env.HYDRA_NETWORK_ID || '0', 10),
@@ -1,6 +1,6 @@
1
- import type { hydraStatus, hydraTransaction } from '@meshsdk/hydra';
2
- import { HydraProvider } from '@meshsdk/hydra';
3
- import type { HeadStatus } from '../hydra/messages.js';
1
+ import { HydraHttpClient } from './hydra/hydra-http-client.js';
2
+ import { HydraWebSocket } from './hydra/hydra-websocket.js';
3
+ import type { HeadStatus, HydraStatus, HydraTransaction } from './hydra/types.js';
4
4
  /** UTxO reference for committing funds into a Hydra head. */
5
5
  export interface UTxORef {
6
6
  /** Transaction hash containing the UTxO. */
@@ -13,17 +13,17 @@ export interface CommitArgs {
13
13
  /** One or more UTxO references to commit. */
14
14
  utxos: UTxORef[];
15
15
  /** Blueprint transaction that spends the committed UTxOs (CBOR-encoded, unsigned). Optional — omit for simple ADA-only commits. */
16
- blueprintTx?: hydraTransaction;
16
+ blueprintTx?: HydraTransaction;
17
17
  }
18
18
  /**
19
19
  * High-level controller for Hydra head lifecycle operations.
20
20
  *
21
- * Wraps `HydraProvider` and `HydraInstance` to provide a simplified API
21
+ * Wraps `HydraWebSocket` and `HydraHttpClient` to provide a simplified API
22
22
  * for initializing, opening, and closing a Hydra head.
23
23
  *
24
24
  * @example
25
25
  * ```ts
26
- * const wrangler = new Wrangler("http://localhost:4001");
26
+ * const wrangler = new Wrangler("http://localhost:4001", "ws://localhost:4001");
27
27
  * await wrangler.waitForHeadOpen({
28
28
  * utxos: [{ txHash: "abc...", outputIndex: 0 }],
29
29
  * blueprintTx: { type: "Tx ConwayEra", cborHex: "...", description: "" },
@@ -32,20 +32,15 @@ export interface CommitArgs {
32
32
  */
33
33
  export declare class Wrangler {
34
34
  private mode;
35
- readonly provider: HydraProvider;
36
- private instance;
35
+ readonly ws: HydraWebSocket;
36
+ readonly http: HydraHttpClient;
37
37
  private readonly blockfrost;
38
- private readonly url;
39
- private readonly wsUrl;
40
38
  constructor(url?: string, wsUrl?: string);
41
- private createHydraProvider;
42
- private createHydraInstance;
43
39
  /**
44
40
  * Connect to the Hydra node with exponential-backoff retry.
45
41
  *
46
- * Uses `HydraProvider.isConnected()` which establishes the WebSocket
47
- * **and** waits for the Hydra `Greetings` handshake, unlike the raw
48
- * `connect()` which only opens the socket.
42
+ * Uses `HydraWebSocket.waitForGreetings()` which establishes the WebSocket
43
+ * **and** waits for the Hydra `Greetings` handshake.
49
44
  *
50
45
  * @param maxAttempts - Maximum number of connection attempts (default 5).
51
46
  * @param baseDelayMs - Initial retry delay in milliseconds (default 1000). Doubles each attempt, capped at 30 s.
@@ -54,16 +49,19 @@ export declare class Wrangler {
54
49
  /**
55
50
  * Shared helper for promise-based methods that wait for a specific
56
51
  * Hydra message. Handles connection, timeout, and settlement in one place.
52
+ *
53
+ * Uses EventEmitter `on`/`removeListener` for multi-listener support,
54
+ * avoiding the single-callback overwrite bug in HydraProvider.
57
55
  */
58
56
  private awaitMessage;
59
- /** Connect the underlying HydraProvider WebSocket with retry logic. */
57
+ /** Connect the underlying WebSocket with retry logic. */
60
58
  connect(): Promise<void>;
61
- /** Disconnect the underlying HydraProvider WebSocket. */
59
+ /** Disconnect the underlying WebSocket. */
62
60
  disconnect(timeout?: number): Promise<void>;
63
- /** Return the current HydraProvider connection/head status. */
64
- getStatus(): hydraStatus;
65
- /** Register a callback for HydraProvider status changes. */
66
- onStatusChange(callback: (status: hydraStatus) => void): hydraStatus;
61
+ /** Return the current Hydra head status (uppercase). */
62
+ getStatus(): HydraStatus;
63
+ /** Register a callback for head status changes. */
64
+ onStatusChange(callback: (status: HydraStatus) => void): HydraStatus;
67
65
  /** Begin the head-opening sequence: init, commit, and listen for state changes. */
68
66
  startHead(commitArgs: CommitArgs): Promise<void>;
69
67
  /** Begin the head-closing sequence: close, fanout, and finalize. */
@@ -89,16 +87,13 @@ export declare class Wrangler {
89
87
  /**
90
88
  * Decommit funds from an open Hydra head back to L1.
91
89
  *
92
- * Posts the decommit transaction via `provider.publishDecommit()` (HTTP POST)
93
- * instead of `provider.decommit()` to avoid overwriting the Wrangler's
94
- * `onMessage` handler (single-callback replacement pattern).
95
- *
90
+ * Posts the decommit transaction via HTTP to avoid overwriting message handlers.
96
91
  * Resolves on `DecommitApproved` — L1 settlement happens asynchronously.
97
92
  *
98
93
  * @param transaction - The decommit transaction (CBOR-encoded).
99
94
  * @param timeoutMs - Maximum time to wait for approval (default 60s).
100
95
  */
101
- decommit(transaction: hydraTransaction, timeoutMs?: number): Promise<void>;
96
+ decommit(transaction: HydraTransaction, timeoutMs?: number): Promise<void>;
102
97
  /**
103
98
  * Incrementally commit funds into an already-open Hydra head.
104
99
  *
@@ -112,6 +107,7 @@ export declare class Wrangler {
112
107
  */
113
108
  incrementalCommit(commitArgs: CommitArgs, timeoutMs?: number): Promise<void>;
114
109
  private doIncrementalCommit;
110
+ private fetchUtxos;
115
111
  private handleIncoming;
116
112
  private onGreetings;
117
113
  }
@@ -1,15 +1,17 @@
1
1
  import { BlockfrostProvider } from '@meshsdk/core';
2
- import { HydraInstance, HydraProvider } from '@meshsdk/hydra';
3
- import { requireEnv } from '../config.js';
2
+ import { requireEnv } from './config.js';
3
+ import { HydraHttpClient } from './hydra/hydra-http-client.js';
4
+ import { HydraWebSocket } from './hydra/hydra-websocket.js';
5
+ import { toHydraUTxO, toHydraUTxOs } from './hydra/utxo-conversion.js';
4
6
  /**
5
7
  * High-level controller for Hydra head lifecycle operations.
6
8
  *
7
- * Wraps `HydraProvider` and `HydraInstance` to provide a simplified API
9
+ * Wraps `HydraWebSocket` and `HydraHttpClient` to provide a simplified API
8
10
  * for initializing, opening, and closing a Hydra head.
9
11
  *
10
12
  * @example
11
13
  * ```ts
12
- * const wrangler = new Wrangler("http://localhost:4001");
14
+ * const wrangler = new Wrangler("http://localhost:4001", "ws://localhost:4001");
13
15
  * await wrangler.waitForHeadOpen({
14
16
  * utxos: [{ txHash: "abc...", outputIndex: 0 }],
15
17
  * blueprintTx: { type: "Tx ConwayEra", cborHex: "...", description: "" },
@@ -18,34 +20,21 @@ import { requireEnv } from '../config.js';
18
20
  */
19
21
  export class Wrangler {
20
22
  mode;
21
- provider;
22
- instance;
23
+ ws;
24
+ http;
23
25
  blockfrost;
24
- url;
25
- wsUrl;
26
26
  constructor(url, wsUrl) {
27
- this.url = url || requireEnv('HYDRA_API_URL');
28
- this.wsUrl = wsUrl || requireEnv('HYDRA_WS_URL');
27
+ const httpUrl = url || requireEnv('HYDRA_API_URL');
28
+ const socketUrl = wsUrl || requireEnv('HYDRA_WS_URL');
29
29
  this.blockfrost = new BlockfrostProvider(requireEnv('BLOCKFROST_API_KEY'));
30
- this.provider = this.createHydraProvider();
31
- this.instance = this.createHydraInstance();
32
- }
33
- createHydraProvider() {
34
- return new HydraProvider({ httpUrl: this.url, history: false });
35
- }
36
- createHydraInstance() {
37
- return new HydraInstance({
38
- provider: this.provider,
39
- fetcher: this.blockfrost,
40
- submitter: this.provider,
41
- });
30
+ this.ws = new HydraWebSocket(socketUrl);
31
+ this.http = new HydraHttpClient(httpUrl);
42
32
  }
43
33
  /**
44
34
  * Connect to the Hydra node with exponential-backoff retry.
45
35
  *
46
- * Uses `HydraProvider.isConnected()` which establishes the WebSocket
47
- * **and** waits for the Hydra `Greetings` handshake, unlike the raw
48
- * `connect()` which only opens the socket.
36
+ * Uses `HydraWebSocket.waitForGreetings()` which establishes the WebSocket
37
+ * **and** waits for the Hydra `Greetings` handshake.
49
38
  *
50
39
  * @param maxAttempts - Maximum number of connection attempts (default 5).
51
40
  * @param baseDelayMs - Initial retry delay in milliseconds (default 1000). Doubles each attempt, capped at 30 s.
@@ -53,10 +42,10 @@ export class Wrangler {
53
42
  async connectWithRetry(maxAttempts = 5, baseDelayMs = 1000) {
54
43
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
55
44
  try {
56
- const connected = await this.provider.isConnected();
45
+ const connected = await this.ws.waitForGreetings();
57
46
  if (connected)
58
47
  return;
59
- throw new Error('isConnected() returned false');
48
+ throw new Error('waitForGreetings() returned false');
60
49
  }
61
50
  catch (err) {
62
51
  if (attempt === maxAttempts - 1) {
@@ -70,6 +59,9 @@ export class Wrangler {
70
59
  /**
71
60
  * Shared helper for promise-based methods that wait for a specific
72
61
  * Hydra message. Handles connection, timeout, and settlement in one place.
62
+ *
63
+ * Uses EventEmitter `on`/`removeListener` for multi-listener support,
64
+ * avoiding the single-callback overwrite bug in HydraProvider.
73
65
  */
74
66
  awaitMessage(handler, timeoutMs, timeoutMessage) {
75
67
  return new Promise((resolve, reject) => {
@@ -79,42 +71,47 @@ export class Wrangler {
79
71
  return;
80
72
  settled = true;
81
73
  clearTimeout(timer);
74
+ this.ws.removeListener('message', onMsg);
82
75
  fn(value);
83
76
  };
84
- this.provider.onMessage((message) => {
85
- handler(message, (value) => settle(resolve, value), (reason) => settle(reject, reason));
86
- });
87
77
  const timer = setTimeout(() => settle(reject, new Error(timeoutMessage)), timeoutMs);
88
- this.connectWithRetry().catch((err) => settle(reject, new Error(`Failed to connect: ${String(err)}`)));
78
+ const onMsg = (message) => {
79
+ handler(message, (value) => settle(resolve, value), (reason) => settle(reject, reason));
80
+ };
81
+ this.connectWithRetry()
82
+ .then(() => {
83
+ this.ws.on('message', onMsg);
84
+ })
85
+ .catch((err) => settle(reject, new Error(`Failed to connect: ${String(err)}`)));
89
86
  });
90
87
  }
91
- /** Connect the underlying HydraProvider WebSocket with retry logic. */
88
+ /** Connect the underlying WebSocket with retry logic. */
92
89
  async connect() {
93
90
  return await this.connectWithRetry();
94
91
  }
95
- /** Disconnect the underlying HydraProvider WebSocket. */
92
+ /** Disconnect the underlying WebSocket. */
96
93
  async disconnect(timeout) {
97
- return this.provider.disconnect(timeout);
94
+ return this.ws.disconnect(timeout);
98
95
  }
99
- /** Return the current HydraProvider connection/head status. */
96
+ /** Return the current Hydra head status (uppercase). */
100
97
  getStatus() {
101
- return this.provider.getStatus();
98
+ return this.ws.getStatus();
102
99
  }
103
- /** Register a callback for HydraProvider status changes. */
100
+ /** Register a callback for head status changes. */
104
101
  onStatusChange(callback) {
105
- return this.provider.onStatusChange(callback);
102
+ return this.ws.onStatusChange(callback);
106
103
  }
107
104
  /** Begin the head-opening sequence: init, commit, and listen for state changes. */
108
105
  async startHead(commitArgs) {
109
106
  this.mode = 'start';
110
- this.provider.onMessage((msg) => this.handleIncoming(msg, commitArgs));
111
107
  await this.connectWithRetry();
108
+ this.ws.on('message', (msg) => this.handleIncoming(msg, commitArgs));
112
109
  }
113
110
  /** Begin the head-closing sequence: close, fanout, and finalize. */
114
111
  async shutdownHead() {
115
112
  this.mode = 'shutdown';
116
- this.provider.onMessage((msg) => this.handleIncoming(msg));
117
113
  await this.connectWithRetry();
114
+ this.ws.on('message', (msg) => this.handleIncoming(msg));
118
115
  }
119
116
  /**
120
117
  * Wait for the Hydra head to fully close and finalize.
@@ -129,7 +126,7 @@ export class Wrangler {
129
126
  resolve();
130
127
  break;
131
128
  case 'ReadyToFanout':
132
- this.provider.fanout();
129
+ this.ws.send({ tag: 'Fanout' });
133
130
  break;
134
131
  case 'Greetings':
135
132
  this.onGreetings(message.headStatus).catch((err) => reject(new Error(`Greetings handler failed: ${String(err)}`)));
@@ -171,29 +168,32 @@ export class Wrangler {
171
168
  }, timeoutMs, 'Timeout waiting for head status');
172
169
  }
173
170
  async doCommit(commitArgs) {
174
- let rawTx;
171
+ let cborHex;
175
172
  if (commitArgs.blueprintTx) {
176
- rawTx = await this.instance.commitBlueprintUTxOs(commitArgs.utxos, commitArgs.blueprintTx);
173
+ const utxos = await this.fetchUtxos(commitArgs.utxos);
174
+ const hydraUtxos = toHydraUTxOs(utxos);
175
+ cborHex = await this.http.buildCommit({ blueprintTx: commitArgs.blueprintTx, utxo: hydraUtxos });
177
176
  }
178
177
  else if (commitArgs.utxos.length === 0) {
179
- rawTx = await this.instance.commitEmpty();
178
+ cborHex = await this.http.buildCommit({});
180
179
  }
181
180
  else if (commitArgs.utxos.length === 1) {
182
181
  const { txHash, outputIndex } = commitArgs.utxos[0];
183
- rawTx = await this.instance.commitFunds(txHash, outputIndex);
182
+ const utxos = await this.blockfrost.fetchUTxOs(txHash, outputIndex);
183
+ if (!utxos[0])
184
+ throw new Error('UTxO not found');
185
+ const hydraUtxo = toHydraUTxO(utxos[0]);
186
+ cborHex = await this.http.buildCommit({ [`${txHash}#${outputIndex}`]: hydraUtxo });
184
187
  }
185
188
  else {
186
189
  throw new Error('Multiple UTxOs without a blueprintTx require a blueprint transaction');
187
190
  }
188
- return await this.blockfrost.submitTx(rawTx);
191
+ return await this.blockfrost.submitTx(cborHex);
189
192
  }
190
193
  /**
191
194
  * Decommit funds from an open Hydra head back to L1.
192
195
  *
193
- * Posts the decommit transaction via `provider.publishDecommit()` (HTTP POST)
194
- * instead of `provider.decommit()` to avoid overwriting the Wrangler's
195
- * `onMessage` handler (single-callback replacement pattern).
196
- *
196
+ * Posts the decommit transaction via HTTP to avoid overwriting message handlers.
197
197
  * Resolves on `DecommitApproved` — L1 settlement happens asynchronously.
198
198
  *
199
199
  * @param transaction - The decommit transaction (CBOR-encoded).
@@ -212,7 +212,7 @@ export class Wrangler {
212
212
  reject(new Error(`Decommit invalid: ${JSON.stringify(message.decommitInvalidReason)}`));
213
213
  }
214
214
  }, timeoutMs, 'Timeout waiting for decommit approval');
215
- await this.provider.publishDecommit(transaction);
215
+ await this.http.publishDecommit(transaction);
216
216
  return result;
217
217
  }
218
218
  /**
@@ -243,14 +243,32 @@ export class Wrangler {
243
243
  throw new Error('Incremental commit requires exactly one UTxO');
244
244
  }
245
245
  const { txHash, outputIndex } = commitArgs.utxos[0];
246
- let rawTx;
246
+ const utxos = await this.blockfrost.fetchUTxOs(txHash, outputIndex);
247
+ if (!utxos[0])
248
+ throw new Error('UTxO not found');
249
+ const hydraUtxo = toHydraUTxO(utxos[0]);
250
+ let cborHex;
247
251
  if (commitArgs.blueprintTx) {
248
- rawTx = await this.instance.incrementalBlueprintCommit(txHash, outputIndex, commitArgs.blueprintTx);
252
+ cborHex = await this.http.buildCommit({
253
+ blueprintTx: commitArgs.blueprintTx,
254
+ utxo: { [`${txHash}#${outputIndex}`]: hydraUtxo },
255
+ });
249
256
  }
250
257
  else {
251
- rawTx = await this.instance.incrementalCommitFunds(txHash, outputIndex);
258
+ cborHex = await this.http.buildCommit({ [`${txHash}#${outputIndex}`]: hydraUtxo });
259
+ }
260
+ return await this.blockfrost.submitTx(cborHex);
261
+ }
262
+ async fetchUtxos(utxoRefs) {
263
+ const results = [];
264
+ for (const { txHash, outputIndex } of utxoRefs) {
265
+ const utxos = await this.blockfrost.fetchUTxOs(txHash, outputIndex);
266
+ if (!utxos.length) {
267
+ throw new Error(`UTxO not found for ${txHash}#${outputIndex}`);
268
+ }
269
+ results.push(...utxos);
252
270
  }
253
- return await this.blockfrost.submitTx(rawTx);
271
+ return results;
254
272
  }
255
273
  async handleIncoming(message, commitArgs) {
256
274
  if (message.tag === 'Greetings') {
@@ -277,7 +295,7 @@ export class Wrangler {
277
295
  break;
278
296
  case 'shutdown':
279
297
  if (message.tag === 'ReadyToFanout') {
280
- await this.provider.fanout();
298
+ this.ws.send({ tag: 'Fanout' });
281
299
  }
282
300
  break;
283
301
  }
@@ -289,7 +307,7 @@ export class Wrangler {
289
307
  switch (status) {
290
308
  case 'Idle':
291
309
  console.log('Idle → init()');
292
- await this.provider.init();
310
+ this.ws.send({ tag: 'Init' });
293
311
  break;
294
312
  case 'Initializing':
295
313
  console.log('Initializing -> commit()');
@@ -310,11 +328,11 @@ export class Wrangler {
310
328
  switch (status) {
311
329
  case 'Open':
312
330
  console.log('Shutting down: closing head…');
313
- await this.provider.close();
331
+ this.ws.send({ tag: 'Close' });
314
332
  break;
315
333
  case 'FanoutPossible':
316
334
  console.log('Fanout now possible: fanning out…');
317
- await this.provider.fanout();
335
+ this.ws.send({ tag: 'Fanout' });
318
336
  break;
319
337
  default:
320
338
  console.log(`Greetings in shutdown mode, ignoring status: ${status}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lerna-labs/hydra-sdk",
3
- "version": "1.0.0-beta.16",
3
+ "version": "1.0.0-beta.18",
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",
@@ -42,10 +42,13 @@
42
42
  "@emurgo/cardano-message-signing-nodejs": "^1.1.0",
43
43
  "@emurgo/cardano-serialization-lib-nodejs": "^15.0.3",
44
44
  "@meshsdk/core": "1.9.0-beta.99",
45
- "@meshsdk/hydra": "1.9.0-beta.99",
46
- "axios": "^1.11.0"
45
+ "@meshsdk/core-cst": "1.9.0-beta.99",
46
+ "axios": "^1.11.0",
47
+ "ws": "^8.18.3"
48
+ },
49
+ "devDependencies": {
50
+ "@types/ws": "^8.18.1"
47
51
  },
48
- "devDependencies": {},
49
52
  "homepage": "https://github.com/Lerna-Labs/hydra-sdk#readme",
50
53
  "bugs": {
51
54
  "url": "https://github.com/Lerna-Labs/hydra-sdk/issues"