@lerna-labs/hydra-sdk 1.0.0-beta.17 → 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,50 +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
77
  const timer = setTimeout(() => settle(reject, new Error(timeoutMessage)), timeoutMs);
85
- // Connect first, then register the message handler. HydraProvider.isConnected()
86
- // internally calls onMessage() (single-callback replacement), which would overwrite
87
- // any handler set beforehand. By connecting first, isConnected() consumes the
88
- // Greetings message via its own handler. Once connected, we register our handler —
89
- // onMessage() replays the _messageQueue, so the Greetings is re-delivered to us.
78
+ const onMsg = (message) => {
79
+ handler(message, (value) => settle(resolve, value), (reason) => settle(reject, reason));
80
+ };
90
81
  this.connectWithRetry()
91
82
  .then(() => {
92
- this.provider.onMessage((message) => {
93
- handler(message, (value) => settle(resolve, value), (reason) => settle(reject, reason));
94
- });
83
+ this.ws.on('message', onMsg);
95
84
  })
96
85
  .catch((err) => settle(reject, new Error(`Failed to connect: ${String(err)}`)));
97
86
  });
98
87
  }
99
- /** Connect the underlying HydraProvider WebSocket with retry logic. */
88
+ /** Connect the underlying WebSocket with retry logic. */
100
89
  async connect() {
101
90
  return await this.connectWithRetry();
102
91
  }
103
- /** Disconnect the underlying HydraProvider WebSocket. */
92
+ /** Disconnect the underlying WebSocket. */
104
93
  async disconnect(timeout) {
105
- return this.provider.disconnect(timeout);
94
+ return this.ws.disconnect(timeout);
106
95
  }
107
- /** Return the current HydraProvider connection/head status. */
96
+ /** Return the current Hydra head status (uppercase). */
108
97
  getStatus() {
109
- return this.provider.getStatus();
98
+ return this.ws.getStatus();
110
99
  }
111
- /** Register a callback for HydraProvider status changes. */
100
+ /** Register a callback for head status changes. */
112
101
  onStatusChange(callback) {
113
- return this.provider.onStatusChange(callback);
102
+ return this.ws.onStatusChange(callback);
114
103
  }
115
104
  /** Begin the head-opening sequence: init, commit, and listen for state changes. */
116
105
  async startHead(commitArgs) {
117
106
  this.mode = 'start';
118
107
  await this.connectWithRetry();
119
- this.provider.onMessage((msg) => this.handleIncoming(msg, commitArgs));
108
+ this.ws.on('message', (msg) => this.handleIncoming(msg, commitArgs));
120
109
  }
121
110
  /** Begin the head-closing sequence: close, fanout, and finalize. */
122
111
  async shutdownHead() {
123
112
  this.mode = 'shutdown';
124
113
  await this.connectWithRetry();
125
- this.provider.onMessage((msg) => this.handleIncoming(msg));
114
+ this.ws.on('message', (msg) => this.handleIncoming(msg));
126
115
  }
127
116
  /**
128
117
  * Wait for the Hydra head to fully close and finalize.
@@ -137,7 +126,7 @@ export class Wrangler {
137
126
  resolve();
138
127
  break;
139
128
  case 'ReadyToFanout':
140
- this.provider.fanout();
129
+ this.ws.send({ tag: 'Fanout' });
141
130
  break;
142
131
  case 'Greetings':
143
132
  this.onGreetings(message.headStatus).catch((err) => reject(new Error(`Greetings handler failed: ${String(err)}`)));
@@ -179,29 +168,32 @@ export class Wrangler {
179
168
  }, timeoutMs, 'Timeout waiting for head status');
180
169
  }
181
170
  async doCommit(commitArgs) {
182
- let rawTx;
171
+ let cborHex;
183
172
  if (commitArgs.blueprintTx) {
184
- 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 });
185
176
  }
186
177
  else if (commitArgs.utxos.length === 0) {
187
- rawTx = await this.instance.commitEmpty();
178
+ cborHex = await this.http.buildCommit({});
188
179
  }
189
180
  else if (commitArgs.utxos.length === 1) {
190
181
  const { txHash, outputIndex } = commitArgs.utxos[0];
191
- 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 });
192
187
  }
193
188
  else {
194
189
  throw new Error('Multiple UTxOs without a blueprintTx require a blueprint transaction');
195
190
  }
196
- return await this.blockfrost.submitTx(rawTx);
191
+ return await this.blockfrost.submitTx(cborHex);
197
192
  }
198
193
  /**
199
194
  * Decommit funds from an open Hydra head back to L1.
200
195
  *
201
- * Posts the decommit transaction via `provider.publishDecommit()` (HTTP POST)
202
- * instead of `provider.decommit()` to avoid overwriting the Wrangler's
203
- * `onMessage` handler (single-callback replacement pattern).
204
- *
196
+ * Posts the decommit transaction via HTTP to avoid overwriting message handlers.
205
197
  * Resolves on `DecommitApproved` — L1 settlement happens asynchronously.
206
198
  *
207
199
  * @param transaction - The decommit transaction (CBOR-encoded).
@@ -220,7 +212,7 @@ export class Wrangler {
220
212
  reject(new Error(`Decommit invalid: ${JSON.stringify(message.decommitInvalidReason)}`));
221
213
  }
222
214
  }, timeoutMs, 'Timeout waiting for decommit approval');
223
- await this.provider.publishDecommit(transaction);
215
+ await this.http.publishDecommit(transaction);
224
216
  return result;
225
217
  }
226
218
  /**
@@ -251,14 +243,32 @@ export class Wrangler {
251
243
  throw new Error('Incremental commit requires exactly one UTxO');
252
244
  }
253
245
  const { txHash, outputIndex } = commitArgs.utxos[0];
254
- 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;
255
251
  if (commitArgs.blueprintTx) {
256
- 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
+ });
257
256
  }
258
257
  else {
259
- 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);
260
270
  }
261
- return await this.blockfrost.submitTx(rawTx);
271
+ return results;
262
272
  }
263
273
  async handleIncoming(message, commitArgs) {
264
274
  if (message.tag === 'Greetings') {
@@ -285,7 +295,7 @@ export class Wrangler {
285
295
  break;
286
296
  case 'shutdown':
287
297
  if (message.tag === 'ReadyToFanout') {
288
- await this.provider.fanout();
298
+ this.ws.send({ tag: 'Fanout' });
289
299
  }
290
300
  break;
291
301
  }
@@ -297,7 +307,7 @@ export class Wrangler {
297
307
  switch (status) {
298
308
  case 'Idle':
299
309
  console.log('Idle → init()');
300
- await this.provider.init();
310
+ this.ws.send({ tag: 'Init' });
301
311
  break;
302
312
  case 'Initializing':
303
313
  console.log('Initializing -> commit()');
@@ -318,11 +328,11 @@ export class Wrangler {
318
328
  switch (status) {
319
329
  case 'Open':
320
330
  console.log('Shutting down: closing head…');
321
- await this.provider.close();
331
+ this.ws.send({ tag: 'Close' });
322
332
  break;
323
333
  case 'FanoutPossible':
324
334
  console.log('Fanout now possible: fanning out…');
325
- await this.provider.fanout();
335
+ this.ws.send({ tag: 'Fanout' });
326
336
  break;
327
337
  default:
328
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.17",
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"