@pear-protocol/core-sdk 0.1.0 → 1.1.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.
@@ -30,6 +30,12 @@ declare class Auth {
30
30
  providerId: string | null;
31
31
  loginMethod: "email" | "evm_wallet";
32
32
  }>;
33
+ apiKeyMe(headers?: ClientHeaders): Promise<{
34
+ id: string;
35
+ role: "basic" | "pro" | "admin";
36
+ scope: "read" | "read_write";
37
+ authMethod: "api_key";
38
+ }>;
33
39
  refreshSession(headers?: ClientHeaders): Promise<void>;
34
40
  refreshToken(body: HttpTypes.RefreshTokenRequest, headers?: ClientHeaders): Promise<{
35
41
  accessToken: string;
@@ -50,6 +50,13 @@ class Auth {
50
50
  headers
51
51
  });
52
52
  }
53
+ // Resolve the identity behind an API key (x-api-key auth). Session-less counterpart to `me`.
54
+ async apiKeyMe(headers) {
55
+ return await this.client.fetch(`/auth/api-key/me`, {
56
+ method: "GET",
57
+ headers
58
+ });
59
+ }
53
60
  async refreshSession(headers) {
54
61
  return await this.client.fetch(`/auth/session/refresh`, {
55
62
  method: "POST",
@@ -4,7 +4,9 @@ import { ClientHeaders } from '../types.js';
4
4
 
5
5
  declare class Core {
6
6
  private client;
7
- constructor(client: HttpClient);
7
+ private clientId?;
8
+ constructor(client: HttpClient, clientId?: string | null);
9
+ private withClientId;
8
10
  accounts: {
9
11
  list: (query?: HttpTypes.TradeAccountListParamsInput, headers?: ClientHeaders) => Promise<{
10
12
  accounts: {
@@ -180,6 +182,25 @@ declare class Core {
180
182
  }>;
181
183
  restore: (id: string, headers?: ClientHeaders) => Promise<void>;
182
184
  };
185
+ apiKeys: {
186
+ list: (headers?: ClientHeaders) => Promise<{
187
+ id: string;
188
+ label: string;
189
+ scope: "read" | "read_write";
190
+ keyPrefix: string;
191
+ lastUsedAt: string | null;
192
+ expiresAt: string | null;
193
+ revokedAt: string | null;
194
+ createdAt: string;
195
+ }[]>;
196
+ create: (body: HttpTypes.CreateApiKeyInput, headers?: ClientHeaders) => Promise<{
197
+ id: string;
198
+ label: string;
199
+ scope: "read" | "read_write";
200
+ key: string;
201
+ }>;
202
+ revoke: (id: string, headers?: ClientHeaders) => Promise<void>;
203
+ };
183
204
  executions: {
184
205
  list: (query: HttpTypes.ExecutionListParamsInput, headers?: ClientHeaders) => Promise<{
185
206
  limit: number;
@@ -456,6 +477,54 @@ declare class Core {
456
477
  }[];
457
478
  }>;
458
479
  };
480
+ notifications: {
481
+ list: (query?: HttpTypes.NotificationListParamsInput, headers?: ClientHeaders) => Promise<{
482
+ notifications: {
483
+ id: string;
484
+ category: "TAKE_PROFIT_HIT" | "STOP_LOSS_HIT" | "TRIGGER_ORDER_HIT";
485
+ parameters: {
486
+ type: "take_profit";
487
+ triggerId: string;
488
+ positionId: string;
489
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
490
+ } | {
491
+ type: "stop_loss";
492
+ triggerId: string;
493
+ positionId: string;
494
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
495
+ } | {
496
+ type: "trigger_order";
497
+ triggerId: string;
498
+ positionId: string;
499
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
500
+ } | {
501
+ type: "default_trigger";
502
+ triggerId: string;
503
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
504
+ };
505
+ isRead: boolean;
506
+ createdAt: string;
507
+ updatedAt: string;
508
+ }[];
509
+ }>;
510
+ markRead: (body: HttpTypes.MarkNotificationsReadPayloadInput, headers?: ClientHeaders) => Promise<{
511
+ updated: number;
512
+ }>;
513
+ markUnread: (body: HttpTypes.MarkNotificationUnreadPayloadInput, headers?: ClientHeaders) => Promise<{
514
+ updated: number;
515
+ }>;
516
+ };
517
+ oracle: {
518
+ btcdom: (headers?: ClientHeaders) => Promise<{
519
+ id: string;
520
+ category: "btcdom";
521
+ source: "coingecko";
522
+ oracle: {
523
+ value: number;
524
+ unit: "cent" | "percent";
525
+ } | null;
526
+ }>;
527
+ };
459
528
  positions: {
460
529
  list: (query: HttpTypes.PositionListParamsInput, headers?: ClientHeaders) => Promise<{
461
530
  positions: {
@@ -1385,6 +1454,29 @@ declare class Core {
1385
1454
  track: "PEAK" | "TROUGH";
1386
1455
  threshold: number;
1387
1456
  };
1457
+ } | {
1458
+ type: "funding_rate";
1459
+ data: {
1460
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1461
+ symbol: string;
1462
+ track: "PEAK" | "TROUGH";
1463
+ threshold: number;
1464
+ };
1465
+ } | {
1466
+ type: "prediction_market";
1467
+ data: {
1468
+ source: "kalshi" | "polymarket";
1469
+ marketKey: string;
1470
+ track: "PEAK" | "TROUGH";
1471
+ threshold: number;
1472
+ };
1473
+ } | {
1474
+ type: "btc_dominance";
1475
+ data: {
1476
+ source: "coingecko";
1477
+ track: "PEAK" | "TROUGH";
1478
+ threshold: number;
1479
+ };
1388
1480
  };
1389
1481
  context: {
1390
1482
  type: "MARKET";
@@ -1486,6 +1578,29 @@ declare class Core {
1486
1578
  track: "PEAK" | "TROUGH";
1487
1579
  threshold: number;
1488
1580
  };
1581
+ } | {
1582
+ type: "funding_rate";
1583
+ data: {
1584
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1585
+ symbol: string;
1586
+ track: "PEAK" | "TROUGH";
1587
+ threshold: number;
1588
+ };
1589
+ } | {
1590
+ type: "prediction_market";
1591
+ data: {
1592
+ source: "kalshi" | "polymarket";
1593
+ marketKey: string;
1594
+ track: "PEAK" | "TROUGH";
1595
+ threshold: number;
1596
+ };
1597
+ } | {
1598
+ type: "btc_dominance";
1599
+ data: {
1600
+ source: "coingecko";
1601
+ track: "PEAK" | "TROUGH";
1602
+ threshold: number;
1603
+ };
1489
1604
  };
1490
1605
  context: {
1491
1606
  type: "MARKET";
@@ -1639,6 +1754,29 @@ declare class Core {
1639
1754
  data: {
1640
1755
  priceSource: "mark" | "mid";
1641
1756
  };
1757
+ } | {
1758
+ type: "funding_rate";
1759
+ data: {
1760
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1761
+ symbol: string;
1762
+ track: "PEAK" | "TROUGH";
1763
+ threshold: number;
1764
+ };
1765
+ } | {
1766
+ type: "prediction_market";
1767
+ data: {
1768
+ source: "kalshi" | "polymarket";
1769
+ marketKey: string;
1770
+ track: "PEAK" | "TROUGH";
1771
+ threshold: number;
1772
+ };
1773
+ } | {
1774
+ type: "btc_dominance";
1775
+ data: {
1776
+ source: "coingecko";
1777
+ track: "PEAK" | "TROUGH";
1778
+ threshold: number;
1779
+ };
1642
1780
  };
1643
1781
  context: {
1644
1782
  type: "MARKET";
@@ -1723,6 +1861,29 @@ declare class Core {
1723
1861
  track: "PEAK" | "TROUGH";
1724
1862
  threshold: number;
1725
1863
  };
1864
+ } | {
1865
+ type: "funding_rate";
1866
+ data: {
1867
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1868
+ symbol: string;
1869
+ track: "PEAK" | "TROUGH";
1870
+ threshold: number;
1871
+ };
1872
+ } | {
1873
+ type: "prediction_market";
1874
+ data: {
1875
+ source: "kalshi" | "polymarket";
1876
+ marketKey: string;
1877
+ track: "PEAK" | "TROUGH";
1878
+ threshold: number;
1879
+ };
1880
+ } | {
1881
+ type: "btc_dominance";
1882
+ data: {
1883
+ source: "coingecko";
1884
+ track: "PEAK" | "TROUGH";
1885
+ threshold: number;
1886
+ };
1726
1887
  };
1727
1888
  context: {
1728
1889
  type: "MARKET";
@@ -1824,6 +1985,29 @@ declare class Core {
1824
1985
  track: "PEAK" | "TROUGH";
1825
1986
  threshold: number;
1826
1987
  };
1988
+ } | {
1989
+ type: "funding_rate";
1990
+ data: {
1991
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1992
+ symbol: string;
1993
+ track: "PEAK" | "TROUGH";
1994
+ threshold: number;
1995
+ };
1996
+ } | {
1997
+ type: "prediction_market";
1998
+ data: {
1999
+ source: "kalshi" | "polymarket";
2000
+ marketKey: string;
2001
+ track: "PEAK" | "TROUGH";
2002
+ threshold: number;
2003
+ };
2004
+ } | {
2005
+ type: "btc_dominance";
2006
+ data: {
2007
+ source: "coingecko";
2008
+ track: "PEAK" | "TROUGH";
2009
+ threshold: number;
2010
+ };
1827
2011
  };
1828
2012
  context: {
1829
2013
  type: "MARKET";
@@ -1977,6 +2161,29 @@ declare class Core {
1977
2161
  data: {
1978
2162
  priceSource: "mark" | "mid";
1979
2163
  };
2164
+ } | {
2165
+ type: "funding_rate";
2166
+ data: {
2167
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
2168
+ symbol: string;
2169
+ track: "PEAK" | "TROUGH";
2170
+ threshold: number;
2171
+ };
2172
+ } | {
2173
+ type: "prediction_market";
2174
+ data: {
2175
+ source: "kalshi" | "polymarket";
2176
+ marketKey: string;
2177
+ track: "PEAK" | "TROUGH";
2178
+ threshold: number;
2179
+ };
2180
+ } | {
2181
+ type: "btc_dominance";
2182
+ data: {
2183
+ source: "coingecko";
2184
+ track: "PEAK" | "TROUGH";
2185
+ threshold: number;
2186
+ };
1980
2187
  };
1981
2188
  context: {
1982
2189
  type: "MARKET";
@@ -2061,6 +2268,29 @@ declare class Core {
2061
2268
  track: "PEAK" | "TROUGH";
2062
2269
  threshold: number;
2063
2270
  };
2271
+ } | {
2272
+ type: "funding_rate";
2273
+ data: {
2274
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
2275
+ symbol: string;
2276
+ track: "PEAK" | "TROUGH";
2277
+ threshold: number;
2278
+ };
2279
+ } | {
2280
+ type: "prediction_market";
2281
+ data: {
2282
+ source: "kalshi" | "polymarket";
2283
+ marketKey: string;
2284
+ track: "PEAK" | "TROUGH";
2285
+ threshold: number;
2286
+ };
2287
+ } | {
2288
+ type: "btc_dominance";
2289
+ data: {
2290
+ source: "coingecko";
2291
+ track: "PEAK" | "TROUGH";
2292
+ threshold: number;
2293
+ };
2064
2294
  };
2065
2295
  context: {
2066
2296
  type: "MARKET";
@@ -2162,6 +2392,29 @@ declare class Core {
2162
2392
  track: "PEAK" | "TROUGH";
2163
2393
  threshold: number;
2164
2394
  };
2395
+ } | {
2396
+ type: "funding_rate";
2397
+ data: {
2398
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
2399
+ symbol: string;
2400
+ track: "PEAK" | "TROUGH";
2401
+ threshold: number;
2402
+ };
2403
+ } | {
2404
+ type: "prediction_market";
2405
+ data: {
2406
+ source: "kalshi" | "polymarket";
2407
+ marketKey: string;
2408
+ track: "PEAK" | "TROUGH";
2409
+ threshold: number;
2410
+ };
2411
+ } | {
2412
+ type: "btc_dominance";
2413
+ data: {
2414
+ source: "coingecko";
2415
+ track: "PEAK" | "TROUGH";
2416
+ threshold: number;
2417
+ };
2165
2418
  };
2166
2419
  context: {
2167
2420
  type: "MARKET";
@@ -2315,6 +2568,29 @@ declare class Core {
2315
2568
  data: {
2316
2569
  priceSource: "mark" | "mid";
2317
2570
  };
2571
+ } | {
2572
+ type: "funding_rate";
2573
+ data: {
2574
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
2575
+ symbol: string;
2576
+ track: "PEAK" | "TROUGH";
2577
+ threshold: number;
2578
+ };
2579
+ } | {
2580
+ type: "prediction_market";
2581
+ data: {
2582
+ source: "kalshi" | "polymarket";
2583
+ marketKey: string;
2584
+ track: "PEAK" | "TROUGH";
2585
+ threshold: number;
2586
+ };
2587
+ } | {
2588
+ type: "btc_dominance";
2589
+ data: {
2590
+ source: "coingecko";
2591
+ track: "PEAK" | "TROUGH";
2592
+ threshold: number;
2593
+ };
2318
2594
  };
2319
2595
  context: {
2320
2596
  type: "MARKET";
@@ -1,7 +1,16 @@
1
1
  class Core {
2
2
  client;
3
- constructor(client) {
3
+ clientId;
4
+ constructor(client, clientId) {
4
5
  this.client = client;
6
+ this.clientId = clientId;
7
+ }
8
+ // Auto-attach the configured attribution clientId to a request body unless the
9
+ // caller already set one explicitly. Bound to the exact trade / trigger / schedule /
10
+ // rebalance payloads it serves, so an unrelated body is a compile error.
11
+ withClientId(body) {
12
+ if (!this.clientId) return body;
13
+ return { clientId: this.clientId, ...body };
5
14
  }
6
15
  accounts = {
7
16
  list: async (query, headers) => {
@@ -33,7 +42,7 @@ class Core {
33
42
  },
34
43
  credentials: async (id, headers) => {
35
44
  return await this.client.fetch(`/trade-accounts/${id}/credentials`, {
36
- method: "GET",
45
+ method: "POST",
37
46
  headers
38
47
  });
39
48
  },
@@ -44,6 +53,27 @@ class Core {
44
53
  });
45
54
  }
46
55
  };
56
+ apiKeys = {
57
+ list: async (headers) => {
58
+ return await this.client.fetch(`/api-keys`, {
59
+ method: "GET",
60
+ headers
61
+ });
62
+ },
63
+ create: async (body, headers) => {
64
+ return await this.client.fetch(`/api-keys`, {
65
+ method: "POST",
66
+ headers,
67
+ body
68
+ });
69
+ },
70
+ revoke: async (id, headers) => {
71
+ return await this.client.fetch(`/api-keys/${id}`, {
72
+ method: "DELETE",
73
+ headers
74
+ });
75
+ }
76
+ };
47
77
  executions = {
48
78
  list: async (query, headers) => {
49
79
  return await this.client.fetch(`/executions`, {
@@ -115,6 +145,37 @@ class Core {
115
145
  });
116
146
  }
117
147
  };
148
+ notifications = {
149
+ list: async (query, headers) => {
150
+ return await this.client.fetch(`/notifications`, {
151
+ method: "GET",
152
+ headers,
153
+ query
154
+ });
155
+ },
156
+ markRead: async (body, headers) => {
157
+ return await this.client.fetch(`/notifications/read`, {
158
+ method: "POST",
159
+ headers,
160
+ body
161
+ });
162
+ },
163
+ markUnread: async (body, headers) => {
164
+ return await this.client.fetch(`/notifications/unread`, {
165
+ method: "POST",
166
+ headers,
167
+ body
168
+ });
169
+ }
170
+ };
171
+ oracle = {
172
+ btcdom: async (headers) => {
173
+ return await this.client.fetch(`/oracle/btcdom`, {
174
+ method: "GET",
175
+ headers
176
+ });
177
+ }
178
+ };
118
179
  positions = {
119
180
  list: async (query, headers) => {
120
181
  return await this.client.fetch(`/positions`, {
@@ -160,7 +221,7 @@ class Core {
160
221
  return await this.client.fetch(`/rebalance/manually/${positionId}`, {
161
222
  method: "POST",
162
223
  headers,
163
- body
224
+ body: this.withClientId(body)
164
225
  });
165
226
  }
166
227
  };
@@ -176,7 +237,7 @@ class Core {
176
237
  return await this.client.fetch(`/schedules`, {
177
238
  method: "POST",
178
239
  headers,
179
- body
240
+ body: this.withClientId(body)
180
241
  });
181
242
  },
182
243
  cancel: async (scheduleId, headers) => {
@@ -227,28 +288,28 @@ class Core {
227
288
  return await this.client.fetch(`/trade/open`, {
228
289
  method: "POST",
229
290
  headers,
230
- body
291
+ body: this.withClientId(body)
231
292
  });
232
293
  },
233
294
  adjust: async (positionId, body, headers) => {
234
295
  return await this.client.fetch(`/trade/${positionId}/adjust`, {
235
296
  method: "POST",
236
297
  headers,
237
- body
298
+ body: this.withClientId(body)
238
299
  });
239
300
  },
240
301
  close: async (positionId, body, headers) => {
241
302
  return await this.client.fetch(`/trade/${positionId}/close`, {
242
303
  method: "POST",
243
304
  headers,
244
- body
305
+ body: this.withClientId(body)
245
306
  });
246
307
  },
247
308
  closeAll: async (body, headers) => {
248
309
  return await this.client.fetch(`/trade/close-all`, {
249
310
  method: "POST",
250
311
  headers,
251
- body
312
+ body: this.withClientId(body)
252
313
  });
253
314
  },
254
315
  setLeverage: async (body, headers) => {
@@ -271,14 +332,14 @@ class Core {
271
332
  return await this.client.fetch(`/triggers/open`, {
272
333
  method: "POST",
273
334
  headers,
274
- body
335
+ body: this.withClientId(body)
275
336
  });
276
337
  },
277
338
  close: async (body, headers) => {
278
339
  return await this.client.fetch(`/triggers/close`, {
279
340
  method: "POST",
280
341
  headers,
281
- body
342
+ body: this.withClientId(body)
282
343
  });
283
344
  },
284
345
  cancel: async (triggerId, headers) => {
@@ -0,0 +1,17 @@
1
+ import { SearchTriggersParams, SearchTriggersResponse } from '@pear-protocol/types';
2
+ export { ExternalTrigger, ExternalTriggerSource, SearchTriggersParams, SearchTriggersResponse, TriggerOutcome } from '@pear-protocol/types';
3
+
4
+ declare class External {
5
+ triggers: {
6
+ kalshi: {
7
+ marketNames: (tickers: string[]) => Promise<Map<string, string>>;
8
+ search: (params?: SearchTriggersParams) => Promise<SearchTriggersResponse>;
9
+ };
10
+ polymarket: {
11
+ marketNames: (ids: string[]) => Promise<Map<string, string>>;
12
+ search: (params?: SearchTriggersParams) => Promise<SearchTriggersResponse>;
13
+ };
14
+ };
15
+ }
16
+
17
+ export { External };
@@ -0,0 +1,25 @@
1
+ import { searchKalshiTriggers, fetchKalshiMarketNames } from './kalshi';
2
+ import { searchPolymarketTriggers, fetchPolymarketMarketNames } from './polymarket';
3
+
4
+ class External {
5
+ triggers = {
6
+ kalshi: {
7
+ marketNames: async (tickers) => {
8
+ return fetchKalshiMarketNames(tickers);
9
+ },
10
+ search: async (params = {}) => {
11
+ return searchKalshiTriggers(params);
12
+ }
13
+ },
14
+ polymarket: {
15
+ marketNames: async (ids) => {
16
+ return fetchPolymarketMarketNames(ids);
17
+ },
18
+ search: async (params = {}) => {
19
+ return searchPolymarketTriggers(params);
20
+ }
21
+ }
22
+ };
23
+ }
24
+
25
+ export { External };
@@ -0,0 +1,6 @@
1
+ import { SearchTriggersParams, SearchTriggersResponse } from '@pear-protocol/types';
2
+
3
+ declare function fetchKalshiMarketNames(tickers: string[]): Promise<Map<string, string>>;
4
+ declare function searchKalshiTriggers(params?: SearchTriggersParams): Promise<SearchTriggersResponse>;
5
+
6
+ export { fetchKalshiMarketNames, searchKalshiTriggers };
@@ -0,0 +1,69 @@
1
+ const BASE_URL = "https://api.elections.kalshi.com";
2
+ const BATCH_SIZE = 100;
3
+ async function fetchKalshiMarketNames(tickers) {
4
+ const result = /* @__PURE__ */ new Map();
5
+ for (let i = 0; i < tickers.length; i += BATCH_SIZE) {
6
+ const batch = tickers.slice(i, i + BATCH_SIZE);
7
+ const url = new URL(`${BASE_URL}/trade-api/v2/markets`);
8
+ url.searchParams.set("tickers", batch.join(","));
9
+ url.searchParams.set("limit", String(BATCH_SIZE));
10
+ const response = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
11
+ if (!response.ok) throw new Error(`Kalshi API error: ${response.status} ${response.statusText}`);
12
+ const data = await response.json();
13
+ for (const m of data.markets ?? []) result.set(m.ticker, m.title);
14
+ }
15
+ return result;
16
+ }
17
+ async function searchKalshiTriggers(params = {}) {
18
+ const url = new URL(`${BASE_URL}/v1/search/series`);
19
+ url.searchParams.set("order_by", "trending");
20
+ url.searchParams.set("status", "open");
21
+ url.searchParams.set("page_size", String(params.pageSize ?? 50));
22
+ if (params.category) url.searchParams.set("category", params.category);
23
+ if (params.search) url.searchParams.set("query", params.search);
24
+ if (params.cursor) url.searchParams.set("cursor", params.cursor);
25
+ const response = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
26
+ if (!response.ok) return { triggers: [], nextCursor: null };
27
+ const data = await response.json();
28
+ return {
29
+ triggers: (data.current_page ?? []).map(mapEventToTrigger),
30
+ nextCursor: data.next_cursor || null
31
+ };
32
+ }
33
+ function mapEventToTrigger(event) {
34
+ const imageUrl = `https://kalshi-public-docs.s3.amazonaws.com/series-images-webp/${event.event_ticker.split("-")[0]}.webp`;
35
+ if (event.markets.length > 1) {
36
+ return {
37
+ id: event.event_ticker,
38
+ category: "prediction_market",
39
+ source: "kalshi",
40
+ selectable: false,
41
+ oracle: null,
42
+ options: event.markets.map(mapMarketToOutcome),
43
+ type: "multi",
44
+ title: event.event_title,
45
+ imageUrl
46
+ };
47
+ }
48
+ const market = event.markets[0];
49
+ return {
50
+ id: market?.ticker ?? event.event_ticker,
51
+ category: "prediction_market",
52
+ source: "kalshi",
53
+ selectable: true,
54
+ oracle: market?.last_price ?? null,
55
+ options: [],
56
+ type: "binary",
57
+ title: event.event_title,
58
+ imageUrl
59
+ };
60
+ }
61
+ function mapMarketToOutcome(market) {
62
+ return {
63
+ id: market.ticker,
64
+ label: market.yes_subtitle || market.title,
65
+ oracle: market.last_price
66
+ };
67
+ }
68
+
69
+ export { fetchKalshiMarketNames, searchKalshiTriggers };
@@ -0,0 +1,6 @@
1
+ import { SearchTriggersParams, SearchTriggersResponse } from '@pear-protocol/types';
2
+
3
+ declare function fetchPolymarketMarketNames(ids: string[]): Promise<Map<string, string>>;
4
+ declare function searchPolymarketTriggers(params?: SearchTriggersParams): Promise<SearchTriggersResponse>;
5
+
6
+ export { fetchPolymarketMarketNames, searchPolymarketTriggers };
@@ -0,0 +1,91 @@
1
+ const BASE_URL = "https://gamma-api.polymarket.com";
2
+ const BATCH_SIZE = 100;
3
+ async function fetchPolymarketMarketNames(ids) {
4
+ const result = /* @__PURE__ */ new Map();
5
+ for (let i = 0; i < ids.length; i += BATCH_SIZE) {
6
+ const batch = ids.slice(i, i + BATCH_SIZE);
7
+ const url = new URL(`${BASE_URL}/markets`);
8
+ for (const id of batch) url.searchParams.append("id", id);
9
+ url.searchParams.set("limit", String(BATCH_SIZE));
10
+ const response = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
11
+ if (!response.ok) throw new Error(`Polymarket API error: ${response.status} ${response.statusText}`);
12
+ const data = await response.json();
13
+ for (const m of data) result.set(m.id, m.question ?? m.groupItemTitle ?? "");
14
+ }
15
+ return result;
16
+ }
17
+ async function searchPolymarketTriggers(params = {}) {
18
+ const url = new URL(`${BASE_URL}/events/keyset`);
19
+ url.searchParams.set("closed", "false");
20
+ url.searchParams.set("limit", String(params.pageSize ?? 50));
21
+ url.searchParams.set("order", "volume24hr");
22
+ url.searchParams.set("ascending", "false");
23
+ if (params.search) url.searchParams.set("title_search", params.search);
24
+ if (params.category) url.searchParams.set("tag_slug", params.category);
25
+ if (params.cursor) url.searchParams.set("after_cursor", params.cursor);
26
+ const response = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
27
+ if (!response.ok) return { triggers: [], nextCursor: null };
28
+ const data = await response.json();
29
+ const events = data.events ?? [];
30
+ return {
31
+ triggers: events.map(mapEventToTrigger).filter((t) => t !== null),
32
+ nextCursor: data.next_cursor ?? null
33
+ };
34
+ }
35
+ function mapEventToTrigger(event) {
36
+ const markets = (event.markets ?? []).filter((m) => m.active !== false && m.closed !== true);
37
+ const [first] = markets;
38
+ if (!first) return null;
39
+ if (markets.length === 1) {
40
+ return {
41
+ id: first.id,
42
+ category: "prediction_market",
43
+ source: "polymarket",
44
+ selectable: true,
45
+ oracle: parseYesCents(first),
46
+ options: [],
47
+ type: "binary",
48
+ title: first.question ?? event.title ?? first.groupItemTitle ?? first.id,
49
+ imageUrl: first.image ?? first.icon ?? event.image ?? event.icon ?? null
50
+ };
51
+ }
52
+ return {
53
+ id: event.id ?? event.slug ?? first.id,
54
+ category: "prediction_market",
55
+ source: "polymarket",
56
+ selectable: false,
57
+ oracle: null,
58
+ options: markets.map(mapMarketToOutcome),
59
+ type: "multi",
60
+ title: event.title ?? first.question ?? event.id,
61
+ imageUrl: event.image ?? event.icon ?? first.image ?? first.icon ?? null
62
+ };
63
+ }
64
+ function mapMarketToOutcome(market) {
65
+ return {
66
+ id: market.id,
67
+ label: market.groupItemTitle ?? market.question ?? market.id,
68
+ oracle: parseYesCents(market)
69
+ };
70
+ }
71
+ function parseYesCents(market) {
72
+ const outcomes = parseStringArray(market.outcomes);
73
+ const prices = parseStringArray(market.outcomePrices);
74
+ const yesIndex = outcomes.findIndex((o) => o.toLowerCase() === "yes");
75
+ if (yesIndex < 0) return null;
76
+ const price = Number(prices[yesIndex] ?? "");
77
+ if (!Number.isFinite(price)) return null;
78
+ return Math.round(price * 1e4) / 100;
79
+ }
80
+ function parseStringArray(value) {
81
+ if (Array.isArray(value)) return value.map(String);
82
+ if (!value) return [];
83
+ try {
84
+ const parsed = JSON.parse(value);
85
+ return Array.isArray(parsed) ? parsed.map(String) : [];
86
+ } catch {
87
+ return [];
88
+ }
89
+ }
90
+
91
+ export { fetchPolymarketMarketNames, searchPolymarketTriggers };
@@ -0,0 +1,49 @@
1
+ export { ExternalTrigger, ExternalTriggerSource, SearchTriggersParams, SearchTriggersResponse, TriggerOutcome } from '@pear-protocol/types';
2
+
3
+ type KalshiMarket = {
4
+ ticker: string;
5
+ title: string;
6
+ };
7
+ type KalshiMarketsResponse = {
8
+ markets: KalshiMarket[];
9
+ };
10
+ type KalshiSearchSeriesMarket = {
11
+ ticker: string;
12
+ yes_subtitle: string;
13
+ last_price: number;
14
+ title: string;
15
+ };
16
+ type KalshiSearchSeriesEvent = {
17
+ event_ticker: string;
18
+ event_title: string;
19
+ markets: KalshiSearchSeriesMarket[];
20
+ };
21
+ type KalshiSearchSeriesResponse = {
22
+ current_page: KalshiSearchSeriesEvent[];
23
+ next_cursor: string;
24
+ };
25
+ type PolymarketMarket = {
26
+ id: string;
27
+ question?: string;
28
+ image?: string;
29
+ icon?: string;
30
+ active?: boolean;
31
+ closed?: boolean;
32
+ groupItemTitle?: string;
33
+ outcomes?: string[] | string;
34
+ outcomePrices?: string[] | string;
35
+ };
36
+ type PolymarketEvent = {
37
+ id: string;
38
+ slug?: string;
39
+ title?: string;
40
+ image?: string;
41
+ icon?: string;
42
+ markets?: PolymarketMarket[];
43
+ };
44
+ type PolymarketKeysetEventsResponse = {
45
+ events?: PolymarketEvent[];
46
+ next_cursor?: string | null;
47
+ };
48
+
49
+ export type { KalshiMarket, KalshiMarketsResponse, KalshiSearchSeriesEvent, KalshiSearchSeriesMarket, KalshiSearchSeriesResponse, PolymarketEvent, PolymarketKeysetEventsResponse, PolymarketMarket };
@@ -0,0 +1 @@
1
+
package/dist/http.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { AuthMode, Logger, RequestMiddleware, ResponseMiddleware, FetchInput, FetchArgs } from './types.js';
2
+ import '@pear-protocol/types';
2
3
 
3
4
  declare class HttpClient {
4
5
  private baseUrl;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { Admin } from './admin/index.js';
2
2
  import { Auth } from './auth/index.js';
3
3
  import { Core } from './core/index.js';
4
+ import { External } from './external/index.js';
4
5
  import { SDKConfig } from './types.js';
5
- export { HttpTypes } from '@pear-protocol/types';
6
+ export { ExternalTrigger, ExternalTriggerSource, HttpTypes, SearchTriggersParams, SearchTriggersResponse, TriggerOutcome } from '@pear-protocol/types';
6
7
  export * from '@pear-protocol/utils';
7
8
  import './http.js';
8
9
 
@@ -10,7 +11,8 @@ declare class PearSDK {
10
11
  admin: Admin;
11
12
  auth: Auth;
12
13
  core: Core;
14
+ external: External;
13
15
  constructor(config: SDKConfig);
14
16
  }
15
17
 
16
- export { PearSDK as default };
18
+ export { External, PearSDK as default };
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Admin } from './admin';
2
2
  import { Auth } from './auth';
3
3
  import { Core } from './core';
4
+ import { External } from './external';
5
+ export { External } from './external';
4
6
  import { HttpClient } from './http';
5
7
  import { FetchError } from './utils';
6
8
  export * from '@pear-protocol/utils';
@@ -9,6 +11,7 @@ class PearSDK {
9
11
  admin;
10
12
  auth;
11
13
  core;
14
+ external;
12
15
  constructor(config) {
13
16
  const authMode = config.auth?.type ?? "session";
14
17
  const logger = config.logger ?? {
@@ -22,6 +25,7 @@ class PearSDK {
22
25
  this.admin = new Admin(client);
23
26
  this.auth = new Auth(client);
24
27
  this.core = new Core(client);
28
+ this.external = new External();
25
29
  if (authMode === "session") {
26
30
  let refreshInFlight = null;
27
31
  const refreshSession = async () => {
@@ -73,6 +77,26 @@ class PearSDK {
73
77
  });
74
78
  }
75
79
  }
80
+ if (authMode === "apikey" && config.auth?.key) {
81
+ const getKey = config.auth.key;
82
+ client.useRequest(async (request, next) => {
83
+ const key = getKey();
84
+ if (key) {
85
+ request.headers.set("x-api-key", key);
86
+ }
87
+ return next();
88
+ });
89
+ if (config.onAuthError) {
90
+ const onAuthError = config.onAuthError;
91
+ client.useResponse(async (response) => {
92
+ if (response.status === 401) {
93
+ onAuthError();
94
+ throw new FetchError("Unauthorized. API key may be expired or revoked.", "Unauthorized", 401);
95
+ }
96
+ return response;
97
+ });
98
+ }
99
+ }
76
100
  if (config.getTradeAccountId) {
77
101
  const getTradeAccountId = config.getTradeAccountId;
78
102
  client.useRequest(async (request, next) => {
package/dist/types.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- type AuthMode = 'session' | 'bearer';
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+
3
+ type AuthMode = 'session' | 'bearer' | 'apikey';
2
4
  type SDKConfig = {
3
5
  /**
4
6
  * API endpoint.
@@ -16,17 +18,28 @@ type SDKConfig = {
16
18
  *
17
19
  * Bearer:
18
20
  * Token set on every request via `Authorization` header. Provide
19
- * `token` getter to supply the API key or JWT. No client-side refresh.
20
- * If 401, caller handles re-auth. Used by headless / API-key clients.
21
+ * `token` getter to supply the JWT. No client-side refresh.
22
+ * If 401, caller handles re-auth. Used by headless JWT clients.
23
+ *
24
+ * Apikey:
25
+ * API key sent on every request via the `x-api-key` header. Provide
26
+ * `key` getter. No cookies, no client-side refresh. If 401, caller
27
+ * handles re-auth. Used by programmatic API-key clients.
21
28
  */
22
29
  auth?: {
23
30
  type: AuthMode;
24
31
  /**
25
- * Token getter for bearer mode (e.g. () => apiKey). Ignored in session mode.
32
+ * Token getter for bearer mode (e.g. () => jwt). Ignored in other modes.
26
33
  *
27
- * Example: () => localStorage.getItem('apiKey')
34
+ * Example: () => localStorage.getItem('accessToken')
28
35
  */
29
36
  token?: () => string | null;
37
+ /**
38
+ * API key getter for apikey mode. Ignored in other modes.
39
+ *
40
+ * Example: () => localStorage.getItem('apiKey')
41
+ */
42
+ key?: () => string | null;
30
43
  };
31
44
  /**
32
45
  * Trade account ID getter (used in both modes)
@@ -35,7 +48,16 @@ type SDKConfig = {
35
48
  */
36
49
  getTradeAccountId?: () => string | null;
37
50
  /**
38
- * Called when server returns 401 (bearer mode only).
51
+ * Default attribution client code (client_ids.code). When set, it is
52
+ * auto-added to the body of trade / trigger / schedule / rebalance requests
53
+ * unless the call already specifies its own `clientId`. `null`/omitted →
54
+ * nothing is added.
55
+ *
56
+ * Example: 'AGENTPEAR'
57
+ */
58
+ clientId?: string | null;
59
+ /**
60
+ * Called when server returns 401 (bearer / apikey mode).
39
61
  *
40
62
  * Example: () => {
41
63
  * console.error('Unauthorized. Token may be expired or revoked.');
@@ -89,5 +111,6 @@ type FetchArgs = Omit<RequestInit, 'headers' | 'body'> & {
89
111
  };
90
112
  type RequestMiddleware = (request: Request, next: () => Promise<Response>) => Promise<Response>;
91
113
  type ResponseMiddleware = (response: Response, retry: () => Promise<Response>, request: Request) => Promise<Response>;
114
+ type ClientIdBody = HttpTypes.RebalanceManually | HttpTypes.CreateSchedule | HttpTypes.CreateTradeOpen | HttpTypes.CreateTradeAdjust | HttpTypes.CreateTradeClose | HttpTypes.CreateTradeCloseAll | HttpTypes.CreateTriggerOpen | HttpTypes.CreateTriggerClose;
92
115
 
93
- export type { AuthMode, ClientHeaders, FetchArgs, FetchInput, FetchParams, Logger, RequestMiddleware, ResponseMiddleware, SDKConfig };
116
+ export type { AuthMode, ClientHeaders, ClientIdBody, FetchArgs, FetchInput, FetchParams, Logger, RequestMiddleware, ResponseMiddleware, SDKConfig };
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { FetchArgs, AuthMode } from './types.js';
2
+ import '@pear-protocol/types';
2
3
 
3
4
  declare function getBaseUrl(passedBaseUrl: string): string;
4
5
  declare function normalizeRequest(init: FetchArgs | undefined, headers: Headers, authMode: AuthMode): RequestInit | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/core-sdk",
3
- "version": "0.1.0",
3
+ "version": "1.1.0",
4
4
  "description": "Pear Protocol Core SDK",
5
5
  "private": false,
6
6
  "type": "module",
@@ -25,8 +25,8 @@
25
25
  "typecheck": "tsc --noEmit"
26
26
  },
27
27
  "dependencies": {
28
- "@pear-protocol/types": "^0.1.0",
29
- "@pear-protocol/utils": "^0.0.22",
28
+ "@pear-protocol/types": "^1.1.0",
29
+ "@pear-protocol/utils": "^0.0.23",
30
30
  "qs": "^6.14.0"
31
31
  },
32
32
  "devDependencies": {