pmxtjs 1.0.0 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/pmxt/client.d.ts +2 -0
- package/dist/esm/pmxt/client.js +33 -7
- package/dist/esm/pmxt/server-manager.d.ts +16 -0
- package/dist/esm/pmxt/server-manager.js +63 -4
- package/dist/pmxt/client.d.ts +2 -0
- package/dist/pmxt/client.js +33 -7
- package/dist/pmxt/server-manager.d.ts +16 -0
- package/dist/pmxt/server-manager.js +63 -4
- package/generated/package.json +1 -1
- package/package.json +4 -1
- package/pmxt/client.ts +36 -8
- package/pmxt/server-manager.ts +74 -4
|
@@ -32,7 +32,9 @@ export declare abstract class Exchange {
|
|
|
32
32
|
protected privateKey?: string;
|
|
33
33
|
protected api: DefaultApi;
|
|
34
34
|
protected serverManager: ServerManager;
|
|
35
|
+
protected initPromise: Promise<void>;
|
|
35
36
|
constructor(exchangeName: string, options?: ExchangeOptions);
|
|
37
|
+
private initializeServer;
|
|
36
38
|
protected handleResponse(response: any): any;
|
|
37
39
|
protected getCredentials(): ExchangeCredentials | undefined;
|
|
38
40
|
/**
|
package/dist/esm/pmxt/client.js
CHANGED
|
@@ -113,25 +113,39 @@ export class Exchange {
|
|
|
113
113
|
privateKey;
|
|
114
114
|
api;
|
|
115
115
|
serverManager;
|
|
116
|
+
initPromise;
|
|
116
117
|
constructor(exchangeName, options = {}) {
|
|
117
118
|
this.exchangeName = exchangeName.toLowerCase();
|
|
118
119
|
this.apiKey = options.apiKey;
|
|
119
120
|
this.privateKey = options.privateKey;
|
|
120
|
-
|
|
121
|
+
let baseUrl = options.baseUrl || "http://localhost:3847";
|
|
121
122
|
const autoStartServer = options.autoStartServer !== false;
|
|
122
123
|
// Initialize server manager
|
|
123
124
|
this.serverManager = new ServerManager({ baseUrl });
|
|
124
|
-
//
|
|
125
|
+
// Configure the API client with the initial base URL (will be updated if port changes)
|
|
126
|
+
const config = new Configuration({ basePath: baseUrl });
|
|
127
|
+
this.api = new DefaultApi(config);
|
|
128
|
+
// Initialize the server connection asynchronously
|
|
129
|
+
this.initPromise = this.initializeServer(autoStartServer);
|
|
130
|
+
}
|
|
131
|
+
async initializeServer(autoStartServer) {
|
|
125
132
|
if (autoStartServer) {
|
|
126
|
-
|
|
133
|
+
try {
|
|
134
|
+
await this.serverManager.ensureServerRunning();
|
|
135
|
+
// Get the actual port the server is running on
|
|
136
|
+
// (may differ from default if default port was busy)
|
|
137
|
+
const actualPort = this.serverManager.getRunningPort();
|
|
138
|
+
const newBaseUrl = `http://localhost:${actualPort}`;
|
|
139
|
+
// Update API client with actual base URL
|
|
140
|
+
const newConfig = new Configuration({ basePath: newBaseUrl });
|
|
141
|
+
this.api = new DefaultApi(newConfig);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
127
144
|
throw new Error(`Failed to start PMXT server: ${error}\n\n` +
|
|
128
145
|
`Please ensure 'pmxt-core' is installed: npm install -g pmxt-core\n` +
|
|
129
146
|
`Or start the server manually: pmxt-server`);
|
|
130
|
-
}
|
|
147
|
+
}
|
|
131
148
|
}
|
|
132
|
-
// Configure the API client
|
|
133
|
-
const config = new Configuration({ basePath: baseUrl });
|
|
134
|
-
this.api = new DefaultApi(config);
|
|
135
149
|
}
|
|
136
150
|
handleResponse(response) {
|
|
137
151
|
if (!response.success) {
|
|
@@ -162,6 +176,7 @@ export class Exchange {
|
|
|
162
176
|
* ```
|
|
163
177
|
*/
|
|
164
178
|
async fetchMarkets(params) {
|
|
179
|
+
await this.initPromise;
|
|
165
180
|
try {
|
|
166
181
|
const args = [];
|
|
167
182
|
if (params) {
|
|
@@ -195,6 +210,7 @@ export class Exchange {
|
|
|
195
210
|
* ```
|
|
196
211
|
*/
|
|
197
212
|
async searchMarkets(query, params) {
|
|
213
|
+
await this.initPromise;
|
|
198
214
|
try {
|
|
199
215
|
const args = [query];
|
|
200
216
|
if (params) {
|
|
@@ -231,6 +247,7 @@ export class Exchange {
|
|
|
231
247
|
* ```
|
|
232
248
|
*/
|
|
233
249
|
async getMarketsBySlug(slug) {
|
|
250
|
+
await this.initPromise;
|
|
234
251
|
try {
|
|
235
252
|
const requestBody = {
|
|
236
253
|
args: [slug],
|
|
@@ -269,6 +286,7 @@ export class Exchange {
|
|
|
269
286
|
* ```
|
|
270
287
|
*/
|
|
271
288
|
async fetchOHLCV(outcomeId, params) {
|
|
289
|
+
await this.initPromise;
|
|
272
290
|
try {
|
|
273
291
|
const paramsDict = { resolution: params.resolution };
|
|
274
292
|
if (params.start) {
|
|
@@ -309,6 +327,7 @@ export class Exchange {
|
|
|
309
327
|
* ```
|
|
310
328
|
*/
|
|
311
329
|
async fetchOrderBook(outcomeId) {
|
|
330
|
+
await this.initPromise;
|
|
312
331
|
try {
|
|
313
332
|
const requestBody = {
|
|
314
333
|
args: [outcomeId],
|
|
@@ -335,6 +354,7 @@ export class Exchange {
|
|
|
335
354
|
* @returns List of trades
|
|
336
355
|
*/
|
|
337
356
|
async fetchTrades(outcomeId, params) {
|
|
357
|
+
await this.initPromise;
|
|
338
358
|
try {
|
|
339
359
|
const paramsDict = { resolution: params.resolution };
|
|
340
360
|
if (params.limit) {
|
|
@@ -375,6 +395,7 @@ export class Exchange {
|
|
|
375
395
|
* ```
|
|
376
396
|
*/
|
|
377
397
|
async createOrder(params) {
|
|
398
|
+
await this.initPromise;
|
|
378
399
|
try {
|
|
379
400
|
const paramsDict = {
|
|
380
401
|
marketId: params.marketId,
|
|
@@ -408,6 +429,7 @@ export class Exchange {
|
|
|
408
429
|
* @returns Cancelled order
|
|
409
430
|
*/
|
|
410
431
|
async cancelOrder(orderId) {
|
|
432
|
+
await this.initPromise;
|
|
411
433
|
try {
|
|
412
434
|
const requestBody = {
|
|
413
435
|
args: [orderId],
|
|
@@ -431,6 +453,7 @@ export class Exchange {
|
|
|
431
453
|
* @returns Order details
|
|
432
454
|
*/
|
|
433
455
|
async fetchOrder(orderId) {
|
|
456
|
+
await this.initPromise;
|
|
434
457
|
try {
|
|
435
458
|
const requestBody = {
|
|
436
459
|
args: [orderId],
|
|
@@ -454,6 +477,7 @@ export class Exchange {
|
|
|
454
477
|
* @returns List of open orders
|
|
455
478
|
*/
|
|
456
479
|
async fetchOpenOrders(marketId) {
|
|
480
|
+
await this.initPromise;
|
|
457
481
|
try {
|
|
458
482
|
const args = [];
|
|
459
483
|
if (marketId) {
|
|
@@ -481,6 +505,7 @@ export class Exchange {
|
|
|
481
505
|
* @returns List of positions
|
|
482
506
|
*/
|
|
483
507
|
async fetchPositions() {
|
|
508
|
+
await this.initPromise;
|
|
484
509
|
try {
|
|
485
510
|
const requestBody = {
|
|
486
511
|
args: [],
|
|
@@ -503,6 +528,7 @@ export class Exchange {
|
|
|
503
528
|
* @returns List of balances (by currency)
|
|
504
529
|
*/
|
|
505
530
|
async fetchBalance() {
|
|
531
|
+
await this.initPromise;
|
|
506
532
|
try {
|
|
507
533
|
const requestBody = {
|
|
508
534
|
args: [],
|
|
@@ -13,7 +13,23 @@ export declare class ServerManager {
|
|
|
13
13
|
private maxRetries;
|
|
14
14
|
private retryDelayMs;
|
|
15
15
|
private api;
|
|
16
|
+
private lockPath;
|
|
17
|
+
private static readonly DEFAULT_PORT;
|
|
16
18
|
constructor(options?: ServerManagerOptions);
|
|
19
|
+
/**
|
|
20
|
+
* Read server information from lock file.
|
|
21
|
+
*/
|
|
22
|
+
private getServerInfo;
|
|
23
|
+
/**
|
|
24
|
+
* Get the actual port the server is running on.
|
|
25
|
+
*
|
|
26
|
+
* This reads the lock file to determine the actual port,
|
|
27
|
+
* which may differ from the default if the default port was busy.
|
|
28
|
+
*/
|
|
29
|
+
getRunningPort(): number;
|
|
30
|
+
/**
|
|
31
|
+
* Check if the server is running.
|
|
32
|
+
*/
|
|
17
33
|
/**
|
|
18
34
|
* Check if the server is running.
|
|
19
35
|
*/
|
|
@@ -4,25 +4,67 @@
|
|
|
4
4
|
* Handles automatic server startup and health checks.
|
|
5
5
|
*/
|
|
6
6
|
import { DefaultApi, Configuration } from "../generated/src/index.js";
|
|
7
|
+
import { readFileSync, existsSync } from "fs";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { join, dirname } from "path";
|
|
7
10
|
export class ServerManager {
|
|
8
11
|
baseUrl;
|
|
9
12
|
maxRetries;
|
|
10
13
|
retryDelayMs;
|
|
11
14
|
api;
|
|
15
|
+
lockPath;
|
|
16
|
+
static DEFAULT_PORT = 3847;
|
|
12
17
|
constructor(options = {}) {
|
|
13
|
-
this.baseUrl = options.baseUrl ||
|
|
18
|
+
this.baseUrl = options.baseUrl || `http://localhost:${ServerManager.DEFAULT_PORT}`;
|
|
14
19
|
this.maxRetries = options.maxRetries || 30;
|
|
15
20
|
this.retryDelayMs = options.retryDelayMs || 1000;
|
|
21
|
+
this.lockPath = join(homedir(), '.pmxt', 'server.lock');
|
|
16
22
|
const config = new Configuration({ basePath: this.baseUrl });
|
|
17
23
|
this.api = new DefaultApi(config);
|
|
18
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Read server information from lock file.
|
|
27
|
+
*/
|
|
28
|
+
getServerInfo() {
|
|
29
|
+
try {
|
|
30
|
+
if (!existsSync(this.lockPath)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const content = readFileSync(this.lockPath, 'utf-8');
|
|
34
|
+
return JSON.parse(content);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get the actual port the server is running on.
|
|
42
|
+
*
|
|
43
|
+
* This reads the lock file to determine the actual port,
|
|
44
|
+
* which may differ from the default if the default port was busy.
|
|
45
|
+
*/
|
|
46
|
+
getRunningPort() {
|
|
47
|
+
const info = this.getServerInfo();
|
|
48
|
+
return info?.port || ServerManager.DEFAULT_PORT;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if the server is running.
|
|
52
|
+
*/
|
|
19
53
|
/**
|
|
20
54
|
* Check if the server is running.
|
|
21
55
|
*/
|
|
22
56
|
async isServerRunning() {
|
|
57
|
+
// Read lock file to get current port
|
|
58
|
+
const port = this.getRunningPort();
|
|
23
59
|
try {
|
|
24
|
-
|
|
25
|
-
|
|
60
|
+
// Use native fetch to check health on the actual running port
|
|
61
|
+
// This avoids issues where this.api is configured with the wrong port
|
|
62
|
+
const response = await fetch(`http://localhost:${port}/health`);
|
|
63
|
+
if (response.ok) {
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
return data.status === "ok";
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
26
68
|
}
|
|
27
69
|
catch (error) {
|
|
28
70
|
return false;
|
|
@@ -48,10 +90,27 @@ export class ServerManager {
|
|
|
48
90
|
if (await this.isServerRunning()) {
|
|
49
91
|
return;
|
|
50
92
|
}
|
|
93
|
+
// Locate pmxt-ensure-server
|
|
94
|
+
let launcherPath = 'pmxt-ensure-server'; // Default to PATH
|
|
95
|
+
try {
|
|
96
|
+
// Try to resolve from pmxt-core dependency
|
|
97
|
+
// For CommonJS build (which is primary), we can use require directly
|
|
98
|
+
// For ESM build, this will be transpiled appropriately
|
|
99
|
+
const corePackageJson = require.resolve('pmxt-core/package.json');
|
|
100
|
+
const coreDir = dirname(corePackageJson);
|
|
101
|
+
const binPath = join(coreDir, 'bin', 'pmxt-ensure-server');
|
|
102
|
+
if (existsSync(binPath)) {
|
|
103
|
+
launcherPath = binPath;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
// If resolution fails, fall back to PATH
|
|
108
|
+
// This could happen in dev environments where pmxt-core is globally installed
|
|
109
|
+
}
|
|
51
110
|
// Try to start the server using pmxt-ensure-server
|
|
52
111
|
const { spawn } = await import("child_process");
|
|
53
112
|
try {
|
|
54
|
-
const proc = spawn(
|
|
113
|
+
const proc = spawn(launcherPath, [], {
|
|
55
114
|
detached: true,
|
|
56
115
|
stdio: "ignore",
|
|
57
116
|
});
|
package/dist/pmxt/client.d.ts
CHANGED
|
@@ -32,7 +32,9 @@ export declare abstract class Exchange {
|
|
|
32
32
|
protected privateKey?: string;
|
|
33
33
|
protected api: DefaultApi;
|
|
34
34
|
protected serverManager: ServerManager;
|
|
35
|
+
protected initPromise: Promise<void>;
|
|
35
36
|
constructor(exchangeName: string, options?: ExchangeOptions);
|
|
37
|
+
private initializeServer;
|
|
36
38
|
protected handleResponse(response: any): any;
|
|
37
39
|
protected getCredentials(): ExchangeCredentials | undefined;
|
|
38
40
|
/**
|
package/dist/pmxt/client.js
CHANGED
|
@@ -116,25 +116,39 @@ class Exchange {
|
|
|
116
116
|
privateKey;
|
|
117
117
|
api;
|
|
118
118
|
serverManager;
|
|
119
|
+
initPromise;
|
|
119
120
|
constructor(exchangeName, options = {}) {
|
|
120
121
|
this.exchangeName = exchangeName.toLowerCase();
|
|
121
122
|
this.apiKey = options.apiKey;
|
|
122
123
|
this.privateKey = options.privateKey;
|
|
123
|
-
|
|
124
|
+
let baseUrl = options.baseUrl || "http://localhost:3847";
|
|
124
125
|
const autoStartServer = options.autoStartServer !== false;
|
|
125
126
|
// Initialize server manager
|
|
126
127
|
this.serverManager = new server_manager_js_1.ServerManager({ baseUrl });
|
|
127
|
-
//
|
|
128
|
+
// Configure the API client with the initial base URL (will be updated if port changes)
|
|
129
|
+
const config = new index_js_1.Configuration({ basePath: baseUrl });
|
|
130
|
+
this.api = new index_js_1.DefaultApi(config);
|
|
131
|
+
// Initialize the server connection asynchronously
|
|
132
|
+
this.initPromise = this.initializeServer(autoStartServer);
|
|
133
|
+
}
|
|
134
|
+
async initializeServer(autoStartServer) {
|
|
128
135
|
if (autoStartServer) {
|
|
129
|
-
|
|
136
|
+
try {
|
|
137
|
+
await this.serverManager.ensureServerRunning();
|
|
138
|
+
// Get the actual port the server is running on
|
|
139
|
+
// (may differ from default if default port was busy)
|
|
140
|
+
const actualPort = this.serverManager.getRunningPort();
|
|
141
|
+
const newBaseUrl = `http://localhost:${actualPort}`;
|
|
142
|
+
// Update API client with actual base URL
|
|
143
|
+
const newConfig = new index_js_1.Configuration({ basePath: newBaseUrl });
|
|
144
|
+
this.api = new index_js_1.DefaultApi(newConfig);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
130
147
|
throw new Error(`Failed to start PMXT server: ${error}\n\n` +
|
|
131
148
|
`Please ensure 'pmxt-core' is installed: npm install -g pmxt-core\n` +
|
|
132
149
|
`Or start the server manually: pmxt-server`);
|
|
133
|
-
}
|
|
150
|
+
}
|
|
134
151
|
}
|
|
135
|
-
// Configure the API client
|
|
136
|
-
const config = new index_js_1.Configuration({ basePath: baseUrl });
|
|
137
|
-
this.api = new index_js_1.DefaultApi(config);
|
|
138
152
|
}
|
|
139
153
|
handleResponse(response) {
|
|
140
154
|
if (!response.success) {
|
|
@@ -165,6 +179,7 @@ class Exchange {
|
|
|
165
179
|
* ```
|
|
166
180
|
*/
|
|
167
181
|
async fetchMarkets(params) {
|
|
182
|
+
await this.initPromise;
|
|
168
183
|
try {
|
|
169
184
|
const args = [];
|
|
170
185
|
if (params) {
|
|
@@ -198,6 +213,7 @@ class Exchange {
|
|
|
198
213
|
* ```
|
|
199
214
|
*/
|
|
200
215
|
async searchMarkets(query, params) {
|
|
216
|
+
await this.initPromise;
|
|
201
217
|
try {
|
|
202
218
|
const args = [query];
|
|
203
219
|
if (params) {
|
|
@@ -234,6 +250,7 @@ class Exchange {
|
|
|
234
250
|
* ```
|
|
235
251
|
*/
|
|
236
252
|
async getMarketsBySlug(slug) {
|
|
253
|
+
await this.initPromise;
|
|
237
254
|
try {
|
|
238
255
|
const requestBody = {
|
|
239
256
|
args: [slug],
|
|
@@ -272,6 +289,7 @@ class Exchange {
|
|
|
272
289
|
* ```
|
|
273
290
|
*/
|
|
274
291
|
async fetchOHLCV(outcomeId, params) {
|
|
292
|
+
await this.initPromise;
|
|
275
293
|
try {
|
|
276
294
|
const paramsDict = { resolution: params.resolution };
|
|
277
295
|
if (params.start) {
|
|
@@ -312,6 +330,7 @@ class Exchange {
|
|
|
312
330
|
* ```
|
|
313
331
|
*/
|
|
314
332
|
async fetchOrderBook(outcomeId) {
|
|
333
|
+
await this.initPromise;
|
|
315
334
|
try {
|
|
316
335
|
const requestBody = {
|
|
317
336
|
args: [outcomeId],
|
|
@@ -338,6 +357,7 @@ class Exchange {
|
|
|
338
357
|
* @returns List of trades
|
|
339
358
|
*/
|
|
340
359
|
async fetchTrades(outcomeId, params) {
|
|
360
|
+
await this.initPromise;
|
|
341
361
|
try {
|
|
342
362
|
const paramsDict = { resolution: params.resolution };
|
|
343
363
|
if (params.limit) {
|
|
@@ -378,6 +398,7 @@ class Exchange {
|
|
|
378
398
|
* ```
|
|
379
399
|
*/
|
|
380
400
|
async createOrder(params) {
|
|
401
|
+
await this.initPromise;
|
|
381
402
|
try {
|
|
382
403
|
const paramsDict = {
|
|
383
404
|
marketId: params.marketId,
|
|
@@ -411,6 +432,7 @@ class Exchange {
|
|
|
411
432
|
* @returns Cancelled order
|
|
412
433
|
*/
|
|
413
434
|
async cancelOrder(orderId) {
|
|
435
|
+
await this.initPromise;
|
|
414
436
|
try {
|
|
415
437
|
const requestBody = {
|
|
416
438
|
args: [orderId],
|
|
@@ -434,6 +456,7 @@ class Exchange {
|
|
|
434
456
|
* @returns Order details
|
|
435
457
|
*/
|
|
436
458
|
async fetchOrder(orderId) {
|
|
459
|
+
await this.initPromise;
|
|
437
460
|
try {
|
|
438
461
|
const requestBody = {
|
|
439
462
|
args: [orderId],
|
|
@@ -457,6 +480,7 @@ class Exchange {
|
|
|
457
480
|
* @returns List of open orders
|
|
458
481
|
*/
|
|
459
482
|
async fetchOpenOrders(marketId) {
|
|
483
|
+
await this.initPromise;
|
|
460
484
|
try {
|
|
461
485
|
const args = [];
|
|
462
486
|
if (marketId) {
|
|
@@ -484,6 +508,7 @@ class Exchange {
|
|
|
484
508
|
* @returns List of positions
|
|
485
509
|
*/
|
|
486
510
|
async fetchPositions() {
|
|
511
|
+
await this.initPromise;
|
|
487
512
|
try {
|
|
488
513
|
const requestBody = {
|
|
489
514
|
args: [],
|
|
@@ -506,6 +531,7 @@ class Exchange {
|
|
|
506
531
|
* @returns List of balances (by currency)
|
|
507
532
|
*/
|
|
508
533
|
async fetchBalance() {
|
|
534
|
+
await this.initPromise;
|
|
509
535
|
try {
|
|
510
536
|
const requestBody = {
|
|
511
537
|
args: [],
|
|
@@ -13,7 +13,23 @@ export declare class ServerManager {
|
|
|
13
13
|
private maxRetries;
|
|
14
14
|
private retryDelayMs;
|
|
15
15
|
private api;
|
|
16
|
+
private lockPath;
|
|
17
|
+
private static readonly DEFAULT_PORT;
|
|
16
18
|
constructor(options?: ServerManagerOptions);
|
|
19
|
+
/**
|
|
20
|
+
* Read server information from lock file.
|
|
21
|
+
*/
|
|
22
|
+
private getServerInfo;
|
|
23
|
+
/**
|
|
24
|
+
* Get the actual port the server is running on.
|
|
25
|
+
*
|
|
26
|
+
* This reads the lock file to determine the actual port,
|
|
27
|
+
* which may differ from the default if the default port was busy.
|
|
28
|
+
*/
|
|
29
|
+
getRunningPort(): number;
|
|
30
|
+
/**
|
|
31
|
+
* Check if the server is running.
|
|
32
|
+
*/
|
|
17
33
|
/**
|
|
18
34
|
* Check if the server is running.
|
|
19
35
|
*/
|
|
@@ -40,25 +40,67 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
41
|
exports.ServerManager = void 0;
|
|
42
42
|
const index_js_1 = require("../generated/src/index.js");
|
|
43
|
+
const fs_1 = require("fs");
|
|
44
|
+
const os_1 = require("os");
|
|
45
|
+
const path_1 = require("path");
|
|
43
46
|
class ServerManager {
|
|
44
47
|
baseUrl;
|
|
45
48
|
maxRetries;
|
|
46
49
|
retryDelayMs;
|
|
47
50
|
api;
|
|
51
|
+
lockPath;
|
|
52
|
+
static DEFAULT_PORT = 3847;
|
|
48
53
|
constructor(options = {}) {
|
|
49
|
-
this.baseUrl = options.baseUrl ||
|
|
54
|
+
this.baseUrl = options.baseUrl || `http://localhost:${ServerManager.DEFAULT_PORT}`;
|
|
50
55
|
this.maxRetries = options.maxRetries || 30;
|
|
51
56
|
this.retryDelayMs = options.retryDelayMs || 1000;
|
|
57
|
+
this.lockPath = (0, path_1.join)((0, os_1.homedir)(), '.pmxt', 'server.lock');
|
|
52
58
|
const config = new index_js_1.Configuration({ basePath: this.baseUrl });
|
|
53
59
|
this.api = new index_js_1.DefaultApi(config);
|
|
54
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Read server information from lock file.
|
|
63
|
+
*/
|
|
64
|
+
getServerInfo() {
|
|
65
|
+
try {
|
|
66
|
+
if (!(0, fs_1.existsSync)(this.lockPath)) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const content = (0, fs_1.readFileSync)(this.lockPath, 'utf-8');
|
|
70
|
+
return JSON.parse(content);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get the actual port the server is running on.
|
|
78
|
+
*
|
|
79
|
+
* This reads the lock file to determine the actual port,
|
|
80
|
+
* which may differ from the default if the default port was busy.
|
|
81
|
+
*/
|
|
82
|
+
getRunningPort() {
|
|
83
|
+
const info = this.getServerInfo();
|
|
84
|
+
return info?.port || ServerManager.DEFAULT_PORT;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check if the server is running.
|
|
88
|
+
*/
|
|
55
89
|
/**
|
|
56
90
|
* Check if the server is running.
|
|
57
91
|
*/
|
|
58
92
|
async isServerRunning() {
|
|
93
|
+
// Read lock file to get current port
|
|
94
|
+
const port = this.getRunningPort();
|
|
59
95
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
96
|
+
// Use native fetch to check health on the actual running port
|
|
97
|
+
// This avoids issues where this.api is configured with the wrong port
|
|
98
|
+
const response = await fetch(`http://localhost:${port}/health`);
|
|
99
|
+
if (response.ok) {
|
|
100
|
+
const data = await response.json();
|
|
101
|
+
return data.status === "ok";
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
62
104
|
}
|
|
63
105
|
catch (error) {
|
|
64
106
|
return false;
|
|
@@ -84,10 +126,27 @@ class ServerManager {
|
|
|
84
126
|
if (await this.isServerRunning()) {
|
|
85
127
|
return;
|
|
86
128
|
}
|
|
129
|
+
// Locate pmxt-ensure-server
|
|
130
|
+
let launcherPath = 'pmxt-ensure-server'; // Default to PATH
|
|
131
|
+
try {
|
|
132
|
+
// Try to resolve from pmxt-core dependency
|
|
133
|
+
// For CommonJS build (which is primary), we can use require directly
|
|
134
|
+
// For ESM build, this will be transpiled appropriately
|
|
135
|
+
const corePackageJson = require.resolve('pmxt-core/package.json');
|
|
136
|
+
const coreDir = (0, path_1.dirname)(corePackageJson);
|
|
137
|
+
const binPath = (0, path_1.join)(coreDir, 'bin', 'pmxt-ensure-server');
|
|
138
|
+
if ((0, fs_1.existsSync)(binPath)) {
|
|
139
|
+
launcherPath = binPath;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
// If resolution fails, fall back to PATH
|
|
144
|
+
// This could happen in dev environments where pmxt-core is globally installed
|
|
145
|
+
}
|
|
87
146
|
// Try to start the server using pmxt-ensure-server
|
|
88
147
|
const { spawn } = await Promise.resolve().then(() => __importStar(require("child_process")));
|
|
89
148
|
try {
|
|
90
|
-
const proc = spawn(
|
|
149
|
+
const proc = spawn(launcherPath, [], {
|
|
91
150
|
detached: true,
|
|
92
151
|
stdio: "ignore",
|
|
93
152
|
});
|
package/generated/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmxtjs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Unified prediction market data API - The ccxt for prediction markets",
|
|
5
5
|
"author": "PMXT Contributors",
|
|
6
6
|
"repository": {
|
|
@@ -41,6 +41,9 @@
|
|
|
41
41
|
"api",
|
|
42
42
|
"unified"
|
|
43
43
|
],
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"pmxt-core": "1.0.3"
|
|
46
|
+
},
|
|
44
47
|
"devDependencies": {
|
|
45
48
|
"@types/jest": "^30.0.0",
|
|
46
49
|
"@types/node": "^20.0.0",
|
package/pmxt/client.ts
CHANGED
|
@@ -172,32 +172,48 @@ export abstract class Exchange {
|
|
|
172
172
|
protected privateKey?: string;
|
|
173
173
|
protected api: DefaultApi;
|
|
174
174
|
protected serverManager: ServerManager;
|
|
175
|
+
protected initPromise: Promise<void>;
|
|
175
176
|
|
|
176
177
|
constructor(exchangeName: string, options: ExchangeOptions = {}) {
|
|
177
178
|
this.exchangeName = exchangeName.toLowerCase();
|
|
178
179
|
this.apiKey = options.apiKey;
|
|
179
180
|
this.privateKey = options.privateKey;
|
|
180
181
|
|
|
181
|
-
|
|
182
|
+
let baseUrl = options.baseUrl || "http://localhost:3847";
|
|
182
183
|
const autoStartServer = options.autoStartServer !== false;
|
|
183
184
|
|
|
184
185
|
// Initialize server manager
|
|
185
186
|
this.serverManager = new ServerManager({ baseUrl });
|
|
186
187
|
|
|
187
|
-
//
|
|
188
|
+
// Configure the API client with the initial base URL (will be updated if port changes)
|
|
189
|
+
const config = new Configuration({ basePath: baseUrl });
|
|
190
|
+
this.api = new DefaultApi(config);
|
|
191
|
+
|
|
192
|
+
// Initialize the server connection asynchronously
|
|
193
|
+
this.initPromise = this.initializeServer(autoStartServer);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private async initializeServer(autoStartServer: boolean): Promise<void> {
|
|
188
197
|
if (autoStartServer) {
|
|
189
|
-
|
|
198
|
+
try {
|
|
199
|
+
await this.serverManager.ensureServerRunning();
|
|
200
|
+
|
|
201
|
+
// Get the actual port the server is running on
|
|
202
|
+
// (may differ from default if default port was busy)
|
|
203
|
+
const actualPort = this.serverManager.getRunningPort();
|
|
204
|
+
const newBaseUrl = `http://localhost:${actualPort}`;
|
|
205
|
+
|
|
206
|
+
// Update API client with actual base URL
|
|
207
|
+
const newConfig = new Configuration({ basePath: newBaseUrl });
|
|
208
|
+
this.api = new DefaultApi(newConfig);
|
|
209
|
+
} catch (error) {
|
|
190
210
|
throw new Error(
|
|
191
211
|
`Failed to start PMXT server: ${error}\n\n` +
|
|
192
212
|
`Please ensure 'pmxt-core' is installed: npm install -g pmxt-core\n` +
|
|
193
213
|
`Or start the server manually: pmxt-server`
|
|
194
214
|
);
|
|
195
|
-
}
|
|
215
|
+
}
|
|
196
216
|
}
|
|
197
|
-
|
|
198
|
-
// Configure the API client
|
|
199
|
-
const config = new Configuration({ basePath: baseUrl });
|
|
200
|
-
this.api = new DefaultApi(config);
|
|
201
217
|
}
|
|
202
218
|
|
|
203
219
|
protected handleResponse(response: any): any {
|
|
@@ -232,6 +248,7 @@ export abstract class Exchange {
|
|
|
232
248
|
* ```
|
|
233
249
|
*/
|
|
234
250
|
async fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]> {
|
|
251
|
+
await this.initPromise;
|
|
235
252
|
try {
|
|
236
253
|
const args: any[] = [];
|
|
237
254
|
if (params) {
|
|
@@ -271,6 +288,7 @@ export abstract class Exchange {
|
|
|
271
288
|
query: string,
|
|
272
289
|
params?: MarketFilterParams
|
|
273
290
|
): Promise<UnifiedMarket[]> {
|
|
291
|
+
await this.initPromise;
|
|
274
292
|
try {
|
|
275
293
|
const args: any[] = [query];
|
|
276
294
|
if (params) {
|
|
@@ -310,6 +328,7 @@ export abstract class Exchange {
|
|
|
310
328
|
* ```
|
|
311
329
|
*/
|
|
312
330
|
async getMarketsBySlug(slug: string): Promise<UnifiedMarket[]> {
|
|
331
|
+
await this.initPromise;
|
|
313
332
|
try {
|
|
314
333
|
const requestBody: GetMarketsBySlugRequest = {
|
|
315
334
|
args: [slug],
|
|
@@ -353,6 +372,7 @@ export abstract class Exchange {
|
|
|
353
372
|
outcomeId: string,
|
|
354
373
|
params: HistoryFilterParams
|
|
355
374
|
): Promise<PriceCandle[]> {
|
|
375
|
+
await this.initPromise;
|
|
356
376
|
try {
|
|
357
377
|
const paramsDict: any = { resolution: params.resolution };
|
|
358
378
|
if (params.start) {
|
|
@@ -396,6 +416,7 @@ export abstract class Exchange {
|
|
|
396
416
|
* ```
|
|
397
417
|
*/
|
|
398
418
|
async fetchOrderBook(outcomeId: string): Promise<OrderBook> {
|
|
419
|
+
await this.initPromise;
|
|
399
420
|
try {
|
|
400
421
|
const requestBody: FetchOrderBookRequest = {
|
|
401
422
|
args: [outcomeId],
|
|
@@ -427,6 +448,7 @@ export abstract class Exchange {
|
|
|
427
448
|
outcomeId: string,
|
|
428
449
|
params: HistoryFilterParams
|
|
429
450
|
): Promise<Trade[]> {
|
|
451
|
+
await this.initPromise;
|
|
430
452
|
try {
|
|
431
453
|
const paramsDict: any = { resolution: params.resolution };
|
|
432
454
|
if (params.limit) {
|
|
@@ -471,6 +493,7 @@ export abstract class Exchange {
|
|
|
471
493
|
* ```
|
|
472
494
|
*/
|
|
473
495
|
async createOrder(params: CreateOrderParams): Promise<Order> {
|
|
496
|
+
await this.initPromise;
|
|
474
497
|
try {
|
|
475
498
|
const paramsDict: any = {
|
|
476
499
|
marketId: params.marketId,
|
|
@@ -507,6 +530,7 @@ export abstract class Exchange {
|
|
|
507
530
|
* @returns Cancelled order
|
|
508
531
|
*/
|
|
509
532
|
async cancelOrder(orderId: string): Promise<Order> {
|
|
533
|
+
await this.initPromise;
|
|
510
534
|
try {
|
|
511
535
|
const requestBody: CancelOrderRequest = {
|
|
512
536
|
args: [orderId],
|
|
@@ -532,6 +556,7 @@ export abstract class Exchange {
|
|
|
532
556
|
* @returns Order details
|
|
533
557
|
*/
|
|
534
558
|
async fetchOrder(orderId: string): Promise<Order> {
|
|
559
|
+
await this.initPromise;
|
|
535
560
|
try {
|
|
536
561
|
const requestBody: CancelOrderRequest = {
|
|
537
562
|
args: [orderId],
|
|
@@ -557,6 +582,7 @@ export abstract class Exchange {
|
|
|
557
582
|
* @returns List of open orders
|
|
558
583
|
*/
|
|
559
584
|
async fetchOpenOrders(marketId?: string): Promise<Order[]> {
|
|
585
|
+
await this.initPromise;
|
|
560
586
|
try {
|
|
561
587
|
const args: any[] = [];
|
|
562
588
|
if (marketId) {
|
|
@@ -588,6 +614,7 @@ export abstract class Exchange {
|
|
|
588
614
|
* @returns List of positions
|
|
589
615
|
*/
|
|
590
616
|
async fetchPositions(): Promise<Position[]> {
|
|
617
|
+
await this.initPromise;
|
|
591
618
|
try {
|
|
592
619
|
const requestBody: FetchPositionsRequest = {
|
|
593
620
|
args: [],
|
|
@@ -612,6 +639,7 @@ export abstract class Exchange {
|
|
|
612
639
|
* @returns List of balances (by currency)
|
|
613
640
|
*/
|
|
614
641
|
async fetchBalance(): Promise<Balance[]> {
|
|
642
|
+
await this.initPromise;
|
|
615
643
|
try {
|
|
616
644
|
const requestBody: FetchPositionsRequest = {
|
|
617
645
|
args: [],
|
package/pmxt/server-manager.ts
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { DefaultApi, Configuration } from "../generated/src/index.js";
|
|
8
|
+
import { readFileSync, existsSync } from "fs";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import { join, dirname } from "path";
|
|
8
11
|
|
|
9
12
|
export interface ServerManagerOptions {
|
|
10
13
|
baseUrl?: string;
|
|
@@ -12,28 +15,75 @@ export interface ServerManagerOptions {
|
|
|
12
15
|
retryDelayMs?: number;
|
|
13
16
|
}
|
|
14
17
|
|
|
18
|
+
interface ServerLockInfo {
|
|
19
|
+
port: number;
|
|
20
|
+
pid: number;
|
|
21
|
+
timestamp: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
export class ServerManager {
|
|
16
25
|
private baseUrl: string;
|
|
17
26
|
private maxRetries: number;
|
|
18
27
|
private retryDelayMs: number;
|
|
19
28
|
private api: DefaultApi;
|
|
29
|
+
private lockPath: string;
|
|
30
|
+
private static readonly DEFAULT_PORT = 3847;
|
|
20
31
|
|
|
21
32
|
constructor(options: ServerManagerOptions = {}) {
|
|
22
|
-
this.baseUrl = options.baseUrl ||
|
|
33
|
+
this.baseUrl = options.baseUrl || `http://localhost:${ServerManager.DEFAULT_PORT}`;
|
|
23
34
|
this.maxRetries = options.maxRetries || 30;
|
|
24
35
|
this.retryDelayMs = options.retryDelayMs || 1000;
|
|
36
|
+
this.lockPath = join(homedir(), '.pmxt', 'server.lock');
|
|
25
37
|
|
|
26
38
|
const config = new Configuration({ basePath: this.baseUrl });
|
|
27
39
|
this.api = new DefaultApi(config);
|
|
28
40
|
}
|
|
29
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Read server information from lock file.
|
|
44
|
+
*/
|
|
45
|
+
private getServerInfo(): ServerLockInfo | null {
|
|
46
|
+
try {
|
|
47
|
+
if (!existsSync(this.lockPath)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const content = readFileSync(this.lockPath, 'utf-8');
|
|
51
|
+
return JSON.parse(content) as ServerLockInfo;
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get the actual port the server is running on.
|
|
59
|
+
*
|
|
60
|
+
* This reads the lock file to determine the actual port,
|
|
61
|
+
* which may differ from the default if the default port was busy.
|
|
62
|
+
*/
|
|
63
|
+
getRunningPort(): number {
|
|
64
|
+
const info = this.getServerInfo();
|
|
65
|
+
return info?.port || ServerManager.DEFAULT_PORT;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if the server is running.
|
|
70
|
+
*/
|
|
30
71
|
/**
|
|
31
72
|
* Check if the server is running.
|
|
32
73
|
*/
|
|
33
74
|
async isServerRunning(): Promise<boolean> {
|
|
75
|
+
// Read lock file to get current port
|
|
76
|
+
const port = this.getRunningPort();
|
|
77
|
+
|
|
34
78
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
79
|
+
// Use native fetch to check health on the actual running port
|
|
80
|
+
// This avoids issues where this.api is configured with the wrong port
|
|
81
|
+
const response = await fetch(`http://localhost:${port}/health`);
|
|
82
|
+
if (response.ok) {
|
|
83
|
+
const data = await response.json();
|
|
84
|
+
return (data as any).status === "ok";
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
37
87
|
} catch (error) {
|
|
38
88
|
return false;
|
|
39
89
|
}
|
|
@@ -63,11 +113,30 @@ export class ServerManager {
|
|
|
63
113
|
return;
|
|
64
114
|
}
|
|
65
115
|
|
|
116
|
+
// Locate pmxt-ensure-server
|
|
117
|
+
let launcherPath = 'pmxt-ensure-server'; // Default to PATH
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// Try to resolve from pmxt-core dependency
|
|
121
|
+
// For CommonJS build (which is primary), we can use require directly
|
|
122
|
+
// For ESM build, this will be transpiled appropriately
|
|
123
|
+
const corePackageJson = require.resolve('pmxt-core/package.json');
|
|
124
|
+
const coreDir = dirname(corePackageJson);
|
|
125
|
+
const binPath = join(coreDir, 'bin', 'pmxt-ensure-server');
|
|
126
|
+
|
|
127
|
+
if (existsSync(binPath)) {
|
|
128
|
+
launcherPath = binPath;
|
|
129
|
+
}
|
|
130
|
+
} catch (error) {
|
|
131
|
+
// If resolution fails, fall back to PATH
|
|
132
|
+
// This could happen in dev environments where pmxt-core is globally installed
|
|
133
|
+
}
|
|
134
|
+
|
|
66
135
|
// Try to start the server using pmxt-ensure-server
|
|
67
136
|
const { spawn } = await import("child_process");
|
|
68
137
|
|
|
69
138
|
try {
|
|
70
|
-
const proc = spawn(
|
|
139
|
+
const proc = spawn(launcherPath, [], {
|
|
71
140
|
detached: true,
|
|
72
141
|
stdio: "ignore",
|
|
73
142
|
});
|
|
@@ -84,3 +153,4 @@ export class ServerManager {
|
|
|
84
153
|
}
|
|
85
154
|
}
|
|
86
155
|
}
|
|
156
|
+
|