polyedge 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +172 -2
- package/dist/index.cjs +643 -0
- package/dist/index.d.cts +1106 -0
- package/dist/index.d.ts +1106 -0
- package/dist/index.js +611 -0
- package/package.json +58 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
// src/stream.ts
|
|
2
|
+
import { EventEmitter } from "events";
|
|
3
|
+
var PolyEdgeStream = class extends EventEmitter {
|
|
4
|
+
streamId;
|
|
5
|
+
apiKey;
|
|
6
|
+
streamBaseUrl;
|
|
7
|
+
heartbeatTimeoutMs;
|
|
8
|
+
initialBackoffMs;
|
|
9
|
+
maxBackoffMs;
|
|
10
|
+
lastEventId = null;
|
|
11
|
+
abortController = null;
|
|
12
|
+
watchdogTimer = null;
|
|
13
|
+
reconnectTimer = null;
|
|
14
|
+
reconnectAttempts = 0;
|
|
15
|
+
isDestroyed = false;
|
|
16
|
+
isConnecting = false;
|
|
17
|
+
// Queue for async iterator support
|
|
18
|
+
asyncQueue = [];
|
|
19
|
+
asyncResolvers = [];
|
|
20
|
+
constructor(streamId, options) {
|
|
21
|
+
super();
|
|
22
|
+
if (!streamId || typeof streamId !== "string") {
|
|
23
|
+
throw new Error("PolyEdgeStream: streamId must be a non-empty string");
|
|
24
|
+
}
|
|
25
|
+
if (!options.apiKey || typeof options.apiKey !== "string") {
|
|
26
|
+
throw new Error("PolyEdgeStream: apiKey must be a non-empty string");
|
|
27
|
+
}
|
|
28
|
+
this.streamId = streamId;
|
|
29
|
+
this.apiKey = options.apiKey;
|
|
30
|
+
this.streamBaseUrl = (options.streamBaseUrl || "https://stream.polyedge.dev").replace(/\/+$/, "");
|
|
31
|
+
this.heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 45e3;
|
|
32
|
+
this.initialBackoffMs = options.initialBackoffMs ?? 1e3;
|
|
33
|
+
this.maxBackoffMs = options.maxBackoffMs ?? 3e4;
|
|
34
|
+
}
|
|
35
|
+
getLastEventId() {
|
|
36
|
+
return this.lastEventId;
|
|
37
|
+
}
|
|
38
|
+
connect() {
|
|
39
|
+
if (this.isDestroyed || this.isConnecting) return;
|
|
40
|
+
this.isConnecting = true;
|
|
41
|
+
this.clearTimers();
|
|
42
|
+
this.abortController = new AbortController();
|
|
43
|
+
const currentSignal = this.abortController.signal;
|
|
44
|
+
const streamUrl = new URL(`${this.streamBaseUrl}/streams/${this.streamId}`);
|
|
45
|
+
if (this.lastEventId) {
|
|
46
|
+
streamUrl.searchParams.set("lastEventId", this.lastEventId);
|
|
47
|
+
}
|
|
48
|
+
const headers = {
|
|
49
|
+
Accept: "text/event-stream",
|
|
50
|
+
"X-PolyEdge-Key": this.apiKey,
|
|
51
|
+
"Cache-Control": "no-cache"
|
|
52
|
+
};
|
|
53
|
+
if (this.lastEventId) {
|
|
54
|
+
headers["Last-Event-ID"] = this.lastEventId;
|
|
55
|
+
}
|
|
56
|
+
this.startWatchdog();
|
|
57
|
+
(async () => {
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetch(streamUrl.toString(), {
|
|
60
|
+
method: "GET",
|
|
61
|
+
headers,
|
|
62
|
+
signal: currentSignal
|
|
63
|
+
});
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
const errText = await response.text().catch(() => "");
|
|
66
|
+
const errMsg = `Stream connection failed with HTTP ${response.status}: ${errText}`;
|
|
67
|
+
const err = new Error(errMsg);
|
|
68
|
+
if ([400, 401, 403, 404].includes(response.status)) {
|
|
69
|
+
this.pushAsync({ err });
|
|
70
|
+
this.emit("error", err);
|
|
71
|
+
this.destroy("fatal_http_status");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
if (!response.body) {
|
|
77
|
+
throw new Error("Response body is null, expected text/event-stream stream");
|
|
78
|
+
}
|
|
79
|
+
this.reconnectAttempts = 0;
|
|
80
|
+
this.isConnecting = false;
|
|
81
|
+
const reader = response.body.getReader();
|
|
82
|
+
const decoder = new TextDecoder("utf-8");
|
|
83
|
+
let buffer = "";
|
|
84
|
+
while (!this.isDestroyed) {
|
|
85
|
+
const { done, value } = await reader.read();
|
|
86
|
+
if (done) break;
|
|
87
|
+
this.resetWatchdog();
|
|
88
|
+
buffer += decoder.decode(value, { stream: true });
|
|
89
|
+
const blocks = buffer.split("\n\n");
|
|
90
|
+
buffer = blocks.pop() ?? "";
|
|
91
|
+
for (const block of blocks) {
|
|
92
|
+
this.parseBlock(block);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!this.isDestroyed) {
|
|
96
|
+
this.scheduleReconnect("stream_eos");
|
|
97
|
+
}
|
|
98
|
+
} catch (err) {
|
|
99
|
+
if (this.isDestroyed || currentSignal.aborted) return;
|
|
100
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
101
|
+
this.scheduleReconnect("network_error");
|
|
102
|
+
} finally {
|
|
103
|
+
this.isConnecting = false;
|
|
104
|
+
}
|
|
105
|
+
})();
|
|
106
|
+
}
|
|
107
|
+
parseBlock(block) {
|
|
108
|
+
const trimmed = block.trim();
|
|
109
|
+
if (!trimmed) return;
|
|
110
|
+
if (trimmed.startsWith(":")) {
|
|
111
|
+
this.emit("heartbeat");
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const lines = trimmed.split("\n");
|
|
115
|
+
let eventId = null;
|
|
116
|
+
let eventType = "message";
|
|
117
|
+
const dataLines = [];
|
|
118
|
+
for (const rawLine of lines) {
|
|
119
|
+
const line = rawLine.trim();
|
|
120
|
+
if (line.startsWith(":")) {
|
|
121
|
+
continue;
|
|
122
|
+
} else if (line.startsWith("id:")) {
|
|
123
|
+
eventId = line.slice(3).trim();
|
|
124
|
+
} else if (line.startsWith("event:")) {
|
|
125
|
+
eventType = line.slice(6).trim();
|
|
126
|
+
} else if (line.startsWith("data:")) {
|
|
127
|
+
dataLines.push(rawLine.slice(rawLine.indexOf("data:") + 5).trimStart());
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (eventId) {
|
|
131
|
+
this.lastEventId = eventId;
|
|
132
|
+
}
|
|
133
|
+
if (eventType === "tx" && dataLines.length > 0) {
|
|
134
|
+
const payloadStr = dataLines.join("\n");
|
|
135
|
+
try {
|
|
136
|
+
const tx = JSON.parse(payloadStr);
|
|
137
|
+
this.pushAsync({ tx });
|
|
138
|
+
this.emit("tx", tx, this.lastEventId ?? "");
|
|
139
|
+
} catch (err) {
|
|
140
|
+
this.emit("error", new Error(`Failed to parse LiveTransaction JSON: ${String(err)}`));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
startWatchdog() {
|
|
145
|
+
this.clearWatchdog();
|
|
146
|
+
this.watchdogTimer = setTimeout(() => {
|
|
147
|
+
this.emit("error", new Error(`SSE Watchdog timed out after ${this.heartbeatTimeoutMs}ms with no bytes/heartbeat received`));
|
|
148
|
+
this.abortController?.abort();
|
|
149
|
+
this.scheduleReconnect("watchdog_timeout");
|
|
150
|
+
}, this.heartbeatTimeoutMs);
|
|
151
|
+
}
|
|
152
|
+
resetWatchdog() {
|
|
153
|
+
if (!this.isDestroyed) {
|
|
154
|
+
this.startWatchdog();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
clearWatchdog() {
|
|
158
|
+
if (this.watchdogTimer) {
|
|
159
|
+
clearTimeout(this.watchdogTimer);
|
|
160
|
+
this.watchdogTimer = null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
clearTimers() {
|
|
164
|
+
this.clearWatchdog();
|
|
165
|
+
if (this.reconnectTimer) {
|
|
166
|
+
clearTimeout(this.reconnectTimer);
|
|
167
|
+
this.reconnectTimer = null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
scheduleReconnect(reason) {
|
|
171
|
+
if (this.isDestroyed) return;
|
|
172
|
+
this.clearTimers();
|
|
173
|
+
this.isConnecting = false;
|
|
174
|
+
this.reconnectAttempts++;
|
|
175
|
+
const exponential = Math.min(
|
|
176
|
+
this.maxBackoffMs,
|
|
177
|
+
this.initialBackoffMs * Math.pow(2, this.reconnectAttempts - 1)
|
|
178
|
+
);
|
|
179
|
+
const jitter = exponential * (0.8 + Math.random() * 0.4);
|
|
180
|
+
const delayMs = Math.round(jitter);
|
|
181
|
+
this.emit("reconnect", this.reconnectAttempts, delayMs);
|
|
182
|
+
this.reconnectTimer = setTimeout(() => {
|
|
183
|
+
this.connect();
|
|
184
|
+
}, delayMs);
|
|
185
|
+
}
|
|
186
|
+
pushAsync(item) {
|
|
187
|
+
this.asyncQueue.push(item);
|
|
188
|
+
const resolver = this.asyncResolvers.shift();
|
|
189
|
+
if (resolver) resolver();
|
|
190
|
+
}
|
|
191
|
+
async *[Symbol.asyncIterator]() {
|
|
192
|
+
if (!this.isConnecting && !this.abortController && !this.isDestroyed) {
|
|
193
|
+
this.connect();
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
while (!this.isDestroyed) {
|
|
197
|
+
while (this.asyncQueue.length > 0) {
|
|
198
|
+
const item = this.asyncQueue.shift();
|
|
199
|
+
if (item.err) throw item.err;
|
|
200
|
+
if (item.done) return;
|
|
201
|
+
if (item.tx) yield item.tx;
|
|
202
|
+
}
|
|
203
|
+
await new Promise((resolve) => {
|
|
204
|
+
this.asyncResolvers.push(resolve);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
} finally {
|
|
208
|
+
this.destroy("async_iterator_break");
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
destroy(reason = "client_destroyed") {
|
|
212
|
+
if (this.isDestroyed) return;
|
|
213
|
+
this.isDestroyed = true;
|
|
214
|
+
this.isConnecting = false;
|
|
215
|
+
this.clearTimers();
|
|
216
|
+
if (this.abortController) {
|
|
217
|
+
this.abortController.abort();
|
|
218
|
+
this.abortController = null;
|
|
219
|
+
}
|
|
220
|
+
this.pushAsync({ done: true });
|
|
221
|
+
this.emit("close", reason);
|
|
222
|
+
this.removeAllListeners();
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// src/client.ts
|
|
227
|
+
var StreamsService = class {
|
|
228
|
+
request;
|
|
229
|
+
apiBaseUrl;
|
|
230
|
+
streamBaseUrl;
|
|
231
|
+
apiKey;
|
|
232
|
+
constructor(request, apiBaseUrl, streamBaseUrl, apiKey) {
|
|
233
|
+
this.request = request;
|
|
234
|
+
this.apiBaseUrl = apiBaseUrl;
|
|
235
|
+
this.streamBaseUrl = streamBaseUrl;
|
|
236
|
+
this.apiKey = apiKey;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Connect to real-time Server-Sent Events (SSE) order execution stream
|
|
240
|
+
* @param streamId Target stream ID
|
|
241
|
+
*/
|
|
242
|
+
connect(streamId, options = {}) {
|
|
243
|
+
const s = new PolyEdgeStream(streamId, {
|
|
244
|
+
apiKey: this.apiKey,
|
|
245
|
+
streamBaseUrl: this.streamBaseUrl,
|
|
246
|
+
...options
|
|
247
|
+
});
|
|
248
|
+
queueMicrotask(() => s.connect());
|
|
249
|
+
return s;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* List User Streams
|
|
253
|
+
* Returns custom and managed real-time trade streams configured by the user.
|
|
254
|
+
* @returns Models.UserStreamsResponse
|
|
255
|
+
*/
|
|
256
|
+
async list() {
|
|
257
|
+
return this.request(this.streamBaseUrl, `/streams`, { method: "GET" });
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Create Filtered Order Stream
|
|
261
|
+
* Provisions a new custom real-time stream with optional address, tag, or series filters.
|
|
262
|
+
* @param req Request payload
|
|
263
|
+
* @returns Models.UserStreamResponse
|
|
264
|
+
*/
|
|
265
|
+
async create(req) {
|
|
266
|
+
return this.request(this.streamBaseUrl, `/streams`, { method: "POST", body: JSON.stringify(req) });
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Get Stream Metadata
|
|
270
|
+
* Fetches metadata, active sessions count, and filter configuration for a specific stream.
|
|
271
|
+
* @param id Stream unique ID
|
|
272
|
+
* @returns Models.UserStreamResponse
|
|
273
|
+
*/
|
|
274
|
+
async get(id) {
|
|
275
|
+
return this.request(this.streamBaseUrl, `/streams/${id}/meta`, { method: "GET" });
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Delete Stream
|
|
279
|
+
* Permanently removes a stream and gracefully disconnects all connected listener sessions.
|
|
280
|
+
* @param id Stream unique ID
|
|
281
|
+
* @returns Models.DeleteStreamResponse
|
|
282
|
+
*/
|
|
283
|
+
async delete(id) {
|
|
284
|
+
return this.request(this.streamBaseUrl, `/streams/${id}`, { method: "DELETE" });
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Update Stream Metadata
|
|
288
|
+
* Updates operational attributes of the stream, such as nickname or enabled/disabled status.
|
|
289
|
+
* @param id Stream unique ID
|
|
290
|
+
* @param req Request payload
|
|
291
|
+
* @returns Models.UserStreamResponse
|
|
292
|
+
*/
|
|
293
|
+
async updateMetadata(id, req) {
|
|
294
|
+
return this.request(this.streamBaseUrl, `/streams/${id}/meta`, { method: "PUT", body: JSON.stringify(req) });
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Update Stream Filter Subscription
|
|
298
|
+
* Dynamically mutates monitored wallet addresses, market tags, or series slugs without disconnecting SSE clients.
|
|
299
|
+
* @param id Stream unique ID
|
|
300
|
+
* @param req Request payload
|
|
301
|
+
* @returns Models.UserStreamResponse
|
|
302
|
+
*/
|
|
303
|
+
async updateSubscription(id, req) {
|
|
304
|
+
return this.request(this.streamBaseUrl, `/streams/${id}/subscription`, { method: "PUT", body: JSON.stringify(req) });
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* List All User Active Sessions
|
|
308
|
+
* Returns all currently connected active SSE listeners for this account.
|
|
309
|
+
* @returns Models.UserActiveSessionsResponse
|
|
310
|
+
*/
|
|
311
|
+
async getActiveSessions() {
|
|
312
|
+
return this.request(this.streamBaseUrl, `/sessions`, { method: "GET" });
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* List User Stream Session History
|
|
316
|
+
* Returns historical SSE connection logs including duration and pushed transactions count.
|
|
317
|
+
* @param params.limit Max records to return
|
|
318
|
+
* @param params.offset Pagination offset
|
|
319
|
+
* @returns Models.UserSessionHistoryResponse
|
|
320
|
+
*/
|
|
321
|
+
async getSessionHistory(params = {}) {
|
|
322
|
+
const query = new URLSearchParams();
|
|
323
|
+
if (params.limit !== void 0) query.set("limit", String(params.limit));
|
|
324
|
+
if (params.offset !== void 0) query.set("offset", String(params.offset));
|
|
325
|
+
const qs = query.toString() ? `?${query.toString()}` : "";
|
|
326
|
+
return this.request(this.streamBaseUrl, `/sessions/history${qs}`, { method: "GET" });
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
var AnalyticsService = class {
|
|
330
|
+
request;
|
|
331
|
+
apiBaseUrl;
|
|
332
|
+
streamBaseUrl;
|
|
333
|
+
apiKey;
|
|
334
|
+
constructor(request, apiBaseUrl, streamBaseUrl, apiKey) {
|
|
335
|
+
this.request = request;
|
|
336
|
+
this.apiBaseUrl = apiBaseUrl;
|
|
337
|
+
this.streamBaseUrl = streamBaseUrl;
|
|
338
|
+
this.apiKey = apiKey;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* 60-Day Trader Deposit Analytics
|
|
342
|
+
* Returns 60-day aggregated deposit summary and individual transaction breakdown for top traders.
|
|
343
|
+
* @param params.limit Max records to return
|
|
344
|
+
* @param params.offset Pagination offset
|
|
345
|
+
* @returns Models.DepositQueryResult
|
|
346
|
+
*/
|
|
347
|
+
async getDeposits(params = {}) {
|
|
348
|
+
const query = new URLSearchParams();
|
|
349
|
+
if (params.limit !== void 0) query.set("limit", String(params.limit));
|
|
350
|
+
if (params.offset !== void 0) query.set("offset", String(params.offset));
|
|
351
|
+
const qs = query.toString() ? `?${query.toString()}` : "";
|
|
352
|
+
return this.request(this.apiBaseUrl, `/v2/analytics/deposits${qs}`, { method: "GET" });
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Top Traders PnL Leaderboard
|
|
356
|
+
* Queries ranked traders across timeframes with PnL, volume, win rate, and performance metrics.
|
|
357
|
+
* @param params.limit Max traders to return
|
|
358
|
+
* @param params.offset Pagination offset
|
|
359
|
+
* @returns Models.LeaderboardResponse
|
|
360
|
+
*/
|
|
361
|
+
async getLeaderboard(params = {}) {
|
|
362
|
+
const query = new URLSearchParams();
|
|
363
|
+
if (params.limit !== void 0) query.set("limit", String(params.limit));
|
|
364
|
+
if (params.offset !== void 0) query.set("offset", String(params.offset));
|
|
365
|
+
const qs = query.toString() ? `?${query.toString()}` : "";
|
|
366
|
+
return this.request(this.apiBaseUrl, `/v2/analytics/leaderboard${qs}`, { method: "GET" });
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Get Prediction Market Detail
|
|
370
|
+
* Fetches standardized market metadata matching on-chain condition IDs and NegRisk parameters.
|
|
371
|
+
* @param id Market numeric ID or condition ID
|
|
372
|
+
* @returns Models.MarketDetailResponse
|
|
373
|
+
*/
|
|
374
|
+
async getMarket(id) {
|
|
375
|
+
return this.request(this.apiBaseUrl, `/v2/markets/${id}`, { method: "GET" });
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Get Trader Intelligence Profile
|
|
379
|
+
* Fetches trader identity dossier, pUSD balance, total PnL, win rates, and ranking metrics.
|
|
380
|
+
* @param address Trader Polygon/Ethereum wallet address
|
|
381
|
+
* @returns Models.TraderProfileResponse
|
|
382
|
+
*/
|
|
383
|
+
async getTrader(address) {
|
|
384
|
+
return this.request(this.apiBaseUrl, `/v2/traders/${address}`, { method: "GET" });
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Get Hourly PnL Equity Curve
|
|
388
|
+
* Provides 1-hour bucketed historical equity curves and trade metrics for a specific trader.
|
|
389
|
+
* @param address Trader Polygon/Ethereum wallet address
|
|
390
|
+
* @returns Models.TraderHourlyStatsResponse
|
|
391
|
+
*/
|
|
392
|
+
async getTraderHourlyStats(address) {
|
|
393
|
+
return this.request(this.apiBaseUrl, `/v2/traders/${address}/hourly_stats`, { method: "GET" });
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Get Trader Market Participation History
|
|
397
|
+
* Queries resolved and active prediction markets traded by the specified wallet address.
|
|
398
|
+
* @param address Trader Polygon/Ethereum wallet address
|
|
399
|
+
* @param params.limit Max markets to return
|
|
400
|
+
* @param params.offset Pagination offset
|
|
401
|
+
* @returns Models.TraderHistoryResponse
|
|
402
|
+
*/
|
|
403
|
+
async getTraderMarkets(address, params = {}) {
|
|
404
|
+
const query = new URLSearchParams();
|
|
405
|
+
if (params.limit !== void 0) query.set("limit", String(params.limit));
|
|
406
|
+
if (params.offset !== void 0) query.set("offset", String(params.offset));
|
|
407
|
+
const qs = query.toString() ? `?${query.toString()}` : "";
|
|
408
|
+
return this.request(this.apiBaseUrl, `/v2/traders/${address}/markets${qs}`, { method: "GET" });
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Get Trader Orders in Market
|
|
412
|
+
* Retrieves granular fill events, side, price, and token outcomes for a trader in a given market.
|
|
413
|
+
* @param address Trader wallet address
|
|
414
|
+
* @param id Market numeric ID
|
|
415
|
+
* @param params.limit Max orders to return
|
|
416
|
+
* @param params.offset Pagination offset
|
|
417
|
+
* @returns Models.UserOrdersResponse
|
|
418
|
+
*/
|
|
419
|
+
async getTraderMarketOrders(address, id, params = {}) {
|
|
420
|
+
const query = new URLSearchParams();
|
|
421
|
+
if (params.limit !== void 0) query.set("limit", String(params.limit));
|
|
422
|
+
if (params.offset !== void 0) query.set("offset", String(params.offset));
|
|
423
|
+
const qs = query.toString() ? `?${query.toString()}` : "";
|
|
424
|
+
return this.request(this.apiBaseUrl, `/v2/traders/${address}/markets/${id}/orders${qs}`, { method: "GET" });
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
var AccountService = class {
|
|
428
|
+
request;
|
|
429
|
+
apiBaseUrl;
|
|
430
|
+
streamBaseUrl;
|
|
431
|
+
apiKey;
|
|
432
|
+
constructor(request, apiBaseUrl, streamBaseUrl, apiKey) {
|
|
433
|
+
this.request = request;
|
|
434
|
+
this.apiBaseUrl = apiBaseUrl;
|
|
435
|
+
this.streamBaseUrl = streamBaseUrl;
|
|
436
|
+
this.apiKey = apiKey;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Get Current Profile
|
|
440
|
+
* Retrieves the authenticated user profile, tier subscription status, and available USDC balance.
|
|
441
|
+
* @returns Models.UserProfile
|
|
442
|
+
*/
|
|
443
|
+
async getProfile() {
|
|
444
|
+
return this.request(this.apiBaseUrl, `/v2/user/me`, { method: "GET" });
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* List API Keys
|
|
448
|
+
* Lists all active and revoked API keys issued to the authenticated account.
|
|
449
|
+
* @returns Models.UserKeysResponse
|
|
450
|
+
*/
|
|
451
|
+
async listKeys() {
|
|
452
|
+
return this.request(this.apiBaseUrl, `/v2/user/keys`, { method: "GET" });
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Create API Key
|
|
456
|
+
* Generates a new authenticated API key token with optional memo label.
|
|
457
|
+
* @param req Request payload
|
|
458
|
+
* @returns Models.UserAPIKey
|
|
459
|
+
*/
|
|
460
|
+
async createKey(req) {
|
|
461
|
+
return this.request(this.apiBaseUrl, `/v2/user/keys`, { method: "POST", body: JSON.stringify(req) });
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Update API Key
|
|
465
|
+
* Modifies label memo or operational status of an existing API key.
|
|
466
|
+
* @param key API key string
|
|
467
|
+
* @param req Request payload
|
|
468
|
+
* @returns Models.UserAPIKey
|
|
469
|
+
*/
|
|
470
|
+
async updateKey(key, req) {
|
|
471
|
+
return this.request(this.apiBaseUrl, `/v2/user/keys/${key}`, { method: "PATCH", body: JSON.stringify(req) });
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Revoke API Key
|
|
475
|
+
* Permanently revokes and deactivates an API key token.
|
|
476
|
+
* @param key API key string
|
|
477
|
+
* @returns Models.DeleteKeyResponse
|
|
478
|
+
*/
|
|
479
|
+
async deleteKey(key) {
|
|
480
|
+
return this.request(this.apiBaseUrl, `/v2/user/keys/${key}`, { method: "DELETE" });
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* List User Balance Ledger
|
|
484
|
+
* Lists chronological ledger entries (subscription billing charges, deposits, withdrawals).
|
|
485
|
+
* @param params.limit Max entries to return
|
|
486
|
+
* @param params.offset Pagination offset
|
|
487
|
+
* @returns Models.UserLedgerResponse
|
|
488
|
+
*/
|
|
489
|
+
async getLedger(params = {}) {
|
|
490
|
+
const query = new URLSearchParams();
|
|
491
|
+
if (params.limit !== void 0) query.set("limit", String(params.limit));
|
|
492
|
+
if (params.offset !== void 0) query.set("offset", String(params.offset));
|
|
493
|
+
const qs = query.toString() ? `?${query.toString()}` : "";
|
|
494
|
+
return this.request(this.apiBaseUrl, `/v2/user/ledger${qs}`, { method: "GET" });
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Get Account Telemetry & Limits
|
|
498
|
+
* Provides live usage statistics, quota limits, and remaining streaming bandwidth.
|
|
499
|
+
* @returns Models.UserTelemetryResponse
|
|
500
|
+
*/
|
|
501
|
+
async getTelemetry() {
|
|
502
|
+
return this.request(this.apiBaseUrl, `/v2/user/telemetry`, { method: "GET" });
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Request Balance Withdrawal
|
|
506
|
+
* Submits a request to withdraw unspent USDC balance to a designated Polygon address.
|
|
507
|
+
* @param req Request payload
|
|
508
|
+
* @returns Models.UserWithdrawResponse
|
|
509
|
+
*/
|
|
510
|
+
async withdraw(req) {
|
|
511
|
+
return this.request(this.apiBaseUrl, `/v2/user/withdraw`, { method: "POST", body: JSON.stringify(req) });
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
var SubscriptionService = class {
|
|
515
|
+
request;
|
|
516
|
+
apiBaseUrl;
|
|
517
|
+
streamBaseUrl;
|
|
518
|
+
apiKey;
|
|
519
|
+
constructor(request, apiBaseUrl, streamBaseUrl, apiKey) {
|
|
520
|
+
this.request = request;
|
|
521
|
+
this.apiBaseUrl = apiBaseUrl;
|
|
522
|
+
this.streamBaseUrl = streamBaseUrl;
|
|
523
|
+
this.apiKey = apiKey;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* List Public Tiers Catalog
|
|
527
|
+
* Returns plan tiers (Free, Starter, Pro, Growth, Whale) with limits and pricing details.
|
|
528
|
+
* @returns Models.Tier[]
|
|
529
|
+
*/
|
|
530
|
+
async listTiers() {
|
|
531
|
+
return this.request(this.apiBaseUrl, `/v2/tiers`, { method: "GET" });
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Get Subscription Quote
|
|
535
|
+
* Calculates prorated billing amounts for subscribing to or upgrading a tier plan.
|
|
536
|
+
* @param req Request payload
|
|
537
|
+
* @returns Models.QuoteSubscriptionResponse
|
|
538
|
+
*/
|
|
539
|
+
async getQuote(req) {
|
|
540
|
+
return this.request(this.apiBaseUrl, `/v2/user/subscribe/quote`, { method: "POST", body: JSON.stringify(req) });
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Purchase / Upgrade Tier Subscription
|
|
544
|
+
* Executes purchase, renewal, or upgrade of an active subscription tier plan.
|
|
545
|
+
* @param req Request payload
|
|
546
|
+
* @returns Models.SubscribeResponse
|
|
547
|
+
*/
|
|
548
|
+
async subscribe(req) {
|
|
549
|
+
return this.request(this.apiBaseUrl, `/v2/user/subscribe`, { method: "POST", body: JSON.stringify(req) });
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Validate Promo Code
|
|
553
|
+
* Verifies validity, discount percentage, and applicable plans for a promotion coupon code.
|
|
554
|
+
* @param req Request payload
|
|
555
|
+
* @returns Models.ValidatePromoCodeResponse
|
|
556
|
+
*/
|
|
557
|
+
async validatePromoCode(req) {
|
|
558
|
+
return this.request(this.apiBaseUrl, `/v2/user/promo-codes/validate`, { method: "POST", body: JSON.stringify(req) });
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
var PolyEdgeClient = class {
|
|
562
|
+
apiKey;
|
|
563
|
+
apiBaseUrl;
|
|
564
|
+
streamBaseUrl;
|
|
565
|
+
/** Streams Service: Real-time SSE trade streaming & filters */
|
|
566
|
+
streams;
|
|
567
|
+
/** Analytics Service: Leaderboard, trader intelligence, markets */
|
|
568
|
+
analytics;
|
|
569
|
+
/** Account Service: Profile, keys, ledger, telemetry */
|
|
570
|
+
account;
|
|
571
|
+
/** Subscription Service: Plan tiers, quotes, checkout */
|
|
572
|
+
subscription;
|
|
573
|
+
constructor(options) {
|
|
574
|
+
if (!options.apiKey) throw new Error("PolyEdgeClient: apiKey is required");
|
|
575
|
+
this.apiKey = options.apiKey;
|
|
576
|
+
this.apiBaseUrl = (options.apiBaseUrl || "https://api.polyedge.dev").replace(/\/+$/, "");
|
|
577
|
+
this.streamBaseUrl = (options.streamBaseUrl || "https://stream.polyedge.dev").replace(/\/+$/, "");
|
|
578
|
+
const req = this.request.bind(this);
|
|
579
|
+
this.streams = new StreamsService(req, this.apiBaseUrl, this.streamBaseUrl, this.apiKey);
|
|
580
|
+
this.analytics = new AnalyticsService(req, this.apiBaseUrl, this.streamBaseUrl, this.apiKey);
|
|
581
|
+
this.account = new AccountService(req, this.apiBaseUrl, this.streamBaseUrl, this.apiKey);
|
|
582
|
+
this.subscription = new SubscriptionService(req, this.apiBaseUrl, this.streamBaseUrl, this.apiKey);
|
|
583
|
+
}
|
|
584
|
+
async request(baseUrl, endpoint, options = {}) {
|
|
585
|
+
const url = `${baseUrl}${endpoint}`;
|
|
586
|
+
const headers = {
|
|
587
|
+
Accept: "application/json",
|
|
588
|
+
"Content-Type": "application/json",
|
|
589
|
+
"X-PolyEdge-Key": this.apiKey,
|
|
590
|
+
...options.headers
|
|
591
|
+
};
|
|
592
|
+
const res = await fetch(url, { ...options, headers });
|
|
593
|
+
if (!res.ok) {
|
|
594
|
+
const body = await res.text().catch(() => "");
|
|
595
|
+
throw new Error(`PolyEdge API Error [${res.status}]: ${body}`);
|
|
596
|
+
}
|
|
597
|
+
return res.json();
|
|
598
|
+
}
|
|
599
|
+
/** Direct helper to create SSE order stream */
|
|
600
|
+
stream(streamId, options = {}) {
|
|
601
|
+
return this.streams.connect(streamId, options);
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
export {
|
|
605
|
+
AccountService,
|
|
606
|
+
AnalyticsService,
|
|
607
|
+
PolyEdgeClient,
|
|
608
|
+
PolyEdgeStream,
|
|
609
|
+
StreamsService,
|
|
610
|
+
SubscriptionService
|
|
611
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,60 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polyedge",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Official TypeScript/Node.js SDK for PolyEdge ultra-low latency Polymarket mempool trade streaming and real-time on-chain analytics API.",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
23
|
+
"test": "node --import tsx --test test/*.test.ts",
|
|
24
|
+
"prepare": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"polymarket",
|
|
28
|
+
"polyedge",
|
|
29
|
+
"polymarket copy trading bot",
|
|
30
|
+
"polymarket trading bot",
|
|
31
|
+
"polymarket copy trade",
|
|
32
|
+
"polymarket smart money",
|
|
33
|
+
"polymarket smart traders",
|
|
34
|
+
"polymarket copy trading",
|
|
35
|
+
"polymarket mempool stream",
|
|
36
|
+
"polymarket pre-block trades",
|
|
37
|
+
"polymarket api",
|
|
38
|
+
"polymarket analytics"
|
|
39
|
+
],
|
|
40
|
+
"author": {
|
|
41
|
+
"name": "PolyEdge Developer Support",
|
|
42
|
+
"email": "dev@polyedge.dev",
|
|
43
|
+
"url": "https://polyedge.dev"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://polyedge.dev",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/PolyEdgeDev/polyedge-ts.git"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/PolyEdgeDev/polyedge-ts/issues"
|
|
52
|
+
},
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^20.11.0",
|
|
56
|
+
"tsx": "^4.7.0",
|
|
57
|
+
"tsup": "^8.0.1",
|
|
58
|
+
"typescript": "^5.3.3"
|
|
59
|
+
}
|
|
60
|
+
}
|