@pear-protocol/core-sdk 0.1.0 → 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.
@@ -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,17 @@ declare class Core {
456
477
  }[];
457
478
  }>;
458
479
  };
480
+ oracle: {
481
+ btcdom: (headers?: ClientHeaders) => Promise<{
482
+ id: string;
483
+ category: "btcdom";
484
+ source: "coingecko";
485
+ oracle: {
486
+ value: number;
487
+ unit: "cent" | "percent";
488
+ } | null;
489
+ }>;
490
+ };
459
491
  positions: {
460
492
  list: (query: HttpTypes.PositionListParamsInput, headers?: ClientHeaders) => Promise<{
461
493
  positions: {
@@ -1385,6 +1417,29 @@ declare class Core {
1385
1417
  track: "PEAK" | "TROUGH";
1386
1418
  threshold: number;
1387
1419
  };
1420
+ } | {
1421
+ type: "funding_rate";
1422
+ data: {
1423
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1424
+ symbol: string;
1425
+ track: "PEAK" | "TROUGH";
1426
+ threshold: number;
1427
+ };
1428
+ } | {
1429
+ type: "prediction_market";
1430
+ data: {
1431
+ source: "kalshi" | "polymarket";
1432
+ marketKey: string;
1433
+ track: "PEAK" | "TROUGH";
1434
+ threshold: number;
1435
+ };
1436
+ } | {
1437
+ type: "btc_dominance";
1438
+ data: {
1439
+ source: "coingecko";
1440
+ track: "PEAK" | "TROUGH";
1441
+ threshold: number;
1442
+ };
1388
1443
  };
1389
1444
  context: {
1390
1445
  type: "MARKET";
@@ -1486,6 +1541,29 @@ declare class Core {
1486
1541
  track: "PEAK" | "TROUGH";
1487
1542
  threshold: number;
1488
1543
  };
1544
+ } | {
1545
+ type: "funding_rate";
1546
+ data: {
1547
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1548
+ symbol: string;
1549
+ track: "PEAK" | "TROUGH";
1550
+ threshold: number;
1551
+ };
1552
+ } | {
1553
+ type: "prediction_market";
1554
+ data: {
1555
+ source: "kalshi" | "polymarket";
1556
+ marketKey: string;
1557
+ track: "PEAK" | "TROUGH";
1558
+ threshold: number;
1559
+ };
1560
+ } | {
1561
+ type: "btc_dominance";
1562
+ data: {
1563
+ source: "coingecko";
1564
+ track: "PEAK" | "TROUGH";
1565
+ threshold: number;
1566
+ };
1489
1567
  };
1490
1568
  context: {
1491
1569
  type: "MARKET";
@@ -1639,6 +1717,29 @@ declare class Core {
1639
1717
  data: {
1640
1718
  priceSource: "mark" | "mid";
1641
1719
  };
1720
+ } | {
1721
+ type: "funding_rate";
1722
+ data: {
1723
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1724
+ symbol: string;
1725
+ track: "PEAK" | "TROUGH";
1726
+ threshold: number;
1727
+ };
1728
+ } | {
1729
+ type: "prediction_market";
1730
+ data: {
1731
+ source: "kalshi" | "polymarket";
1732
+ marketKey: string;
1733
+ track: "PEAK" | "TROUGH";
1734
+ threshold: number;
1735
+ };
1736
+ } | {
1737
+ type: "btc_dominance";
1738
+ data: {
1739
+ source: "coingecko";
1740
+ track: "PEAK" | "TROUGH";
1741
+ threshold: number;
1742
+ };
1642
1743
  };
1643
1744
  context: {
1644
1745
  type: "MARKET";
@@ -1723,6 +1824,29 @@ declare class Core {
1723
1824
  track: "PEAK" | "TROUGH";
1724
1825
  threshold: number;
1725
1826
  };
1827
+ } | {
1828
+ type: "funding_rate";
1829
+ data: {
1830
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1831
+ symbol: string;
1832
+ track: "PEAK" | "TROUGH";
1833
+ threshold: number;
1834
+ };
1835
+ } | {
1836
+ type: "prediction_market";
1837
+ data: {
1838
+ source: "kalshi" | "polymarket";
1839
+ marketKey: string;
1840
+ track: "PEAK" | "TROUGH";
1841
+ threshold: number;
1842
+ };
1843
+ } | {
1844
+ type: "btc_dominance";
1845
+ data: {
1846
+ source: "coingecko";
1847
+ track: "PEAK" | "TROUGH";
1848
+ threshold: number;
1849
+ };
1726
1850
  };
1727
1851
  context: {
1728
1852
  type: "MARKET";
@@ -1824,6 +1948,29 @@ declare class Core {
1824
1948
  track: "PEAK" | "TROUGH";
1825
1949
  threshold: number;
1826
1950
  };
1951
+ } | {
1952
+ type: "funding_rate";
1953
+ data: {
1954
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
1955
+ symbol: string;
1956
+ track: "PEAK" | "TROUGH";
1957
+ threshold: number;
1958
+ };
1959
+ } | {
1960
+ type: "prediction_market";
1961
+ data: {
1962
+ source: "kalshi" | "polymarket";
1963
+ marketKey: string;
1964
+ track: "PEAK" | "TROUGH";
1965
+ threshold: number;
1966
+ };
1967
+ } | {
1968
+ type: "btc_dominance";
1969
+ data: {
1970
+ source: "coingecko";
1971
+ track: "PEAK" | "TROUGH";
1972
+ threshold: number;
1973
+ };
1827
1974
  };
1828
1975
  context: {
1829
1976
  type: "MARKET";
@@ -1977,6 +2124,29 @@ declare class Core {
1977
2124
  data: {
1978
2125
  priceSource: "mark" | "mid";
1979
2126
  };
2127
+ } | {
2128
+ type: "funding_rate";
2129
+ data: {
2130
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
2131
+ symbol: string;
2132
+ track: "PEAK" | "TROUGH";
2133
+ threshold: number;
2134
+ };
2135
+ } | {
2136
+ type: "prediction_market";
2137
+ data: {
2138
+ source: "kalshi" | "polymarket";
2139
+ marketKey: string;
2140
+ track: "PEAK" | "TROUGH";
2141
+ threshold: number;
2142
+ };
2143
+ } | {
2144
+ type: "btc_dominance";
2145
+ data: {
2146
+ source: "coingecko";
2147
+ track: "PEAK" | "TROUGH";
2148
+ threshold: number;
2149
+ };
1980
2150
  };
1981
2151
  context: {
1982
2152
  type: "MARKET";
@@ -2061,6 +2231,29 @@ declare class Core {
2061
2231
  track: "PEAK" | "TROUGH";
2062
2232
  threshold: number;
2063
2233
  };
2234
+ } | {
2235
+ type: "funding_rate";
2236
+ data: {
2237
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
2238
+ symbol: string;
2239
+ track: "PEAK" | "TROUGH";
2240
+ threshold: number;
2241
+ };
2242
+ } | {
2243
+ type: "prediction_market";
2244
+ data: {
2245
+ source: "kalshi" | "polymarket";
2246
+ marketKey: string;
2247
+ track: "PEAK" | "TROUGH";
2248
+ threshold: number;
2249
+ };
2250
+ } | {
2251
+ type: "btc_dominance";
2252
+ data: {
2253
+ source: "coingecko";
2254
+ track: "PEAK" | "TROUGH";
2255
+ threshold: number;
2256
+ };
2064
2257
  };
2065
2258
  context: {
2066
2259
  type: "MARKET";
@@ -2162,6 +2355,29 @@ declare class Core {
2162
2355
  track: "PEAK" | "TROUGH";
2163
2356
  threshold: number;
2164
2357
  };
2358
+ } | {
2359
+ type: "funding_rate";
2360
+ data: {
2361
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
2362
+ symbol: string;
2363
+ track: "PEAK" | "TROUGH";
2364
+ threshold: number;
2365
+ };
2366
+ } | {
2367
+ type: "prediction_market";
2368
+ data: {
2369
+ source: "kalshi" | "polymarket";
2370
+ marketKey: string;
2371
+ track: "PEAK" | "TROUGH";
2372
+ threshold: number;
2373
+ };
2374
+ } | {
2375
+ type: "btc_dominance";
2376
+ data: {
2377
+ source: "coingecko";
2378
+ track: "PEAK" | "TROUGH";
2379
+ threshold: number;
2380
+ };
2165
2381
  };
2166
2382
  context: {
2167
2383
  type: "MARKET";
@@ -2315,6 +2531,29 @@ declare class Core {
2315
2531
  data: {
2316
2532
  priceSource: "mark" | "mid";
2317
2533
  };
2534
+ } | {
2535
+ type: "funding_rate";
2536
+ data: {
2537
+ connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
2538
+ symbol: string;
2539
+ track: "PEAK" | "TROUGH";
2540
+ threshold: number;
2541
+ };
2542
+ } | {
2543
+ type: "prediction_market";
2544
+ data: {
2545
+ source: "kalshi" | "polymarket";
2546
+ marketKey: string;
2547
+ track: "PEAK" | "TROUGH";
2548
+ threshold: number;
2549
+ };
2550
+ } | {
2551
+ type: "btc_dominance";
2552
+ data: {
2553
+ source: "coingecko";
2554
+ track: "PEAK" | "TROUGH";
2555
+ threshold: number;
2556
+ };
2318
2557
  };
2319
2558
  context: {
2320
2559
  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,14 @@ class Core {
115
145
  });
116
146
  }
117
147
  };
148
+ oracle = {
149
+ btcdom: async (headers) => {
150
+ return await this.client.fetch(`/oracle/btcdom`, {
151
+ method: "GET",
152
+ headers
153
+ });
154
+ }
155
+ };
118
156
  positions = {
119
157
  list: async (query, headers) => {
120
158
  return await this.client.fetch(`/positions`, {
@@ -160,7 +198,7 @@ class Core {
160
198
  return await this.client.fetch(`/rebalance/manually/${positionId}`, {
161
199
  method: "POST",
162
200
  headers,
163
- body
201
+ body: this.withClientId(body)
164
202
  });
165
203
  }
166
204
  };
@@ -176,7 +214,7 @@ class Core {
176
214
  return await this.client.fetch(`/schedules`, {
177
215
  method: "POST",
178
216
  headers,
179
- body
217
+ body: this.withClientId(body)
180
218
  });
181
219
  },
182
220
  cancel: async (scheduleId, headers) => {
@@ -227,28 +265,28 @@ class Core {
227
265
  return await this.client.fetch(`/trade/open`, {
228
266
  method: "POST",
229
267
  headers,
230
- body
268
+ body: this.withClientId(body)
231
269
  });
232
270
  },
233
271
  adjust: async (positionId, body, headers) => {
234
272
  return await this.client.fetch(`/trade/${positionId}/adjust`, {
235
273
  method: "POST",
236
274
  headers,
237
- body
275
+ body: this.withClientId(body)
238
276
  });
239
277
  },
240
278
  close: async (positionId, body, headers) => {
241
279
  return await this.client.fetch(`/trade/${positionId}/close`, {
242
280
  method: "POST",
243
281
  headers,
244
- body
282
+ body: this.withClientId(body)
245
283
  });
246
284
  },
247
285
  closeAll: async (body, headers) => {
248
286
  return await this.client.fetch(`/trade/close-all`, {
249
287
  method: "POST",
250
288
  headers,
251
- body
289
+ body: this.withClientId(body)
252
290
  });
253
291
  },
254
292
  setLeverage: async (body, headers) => {
@@ -271,14 +309,14 @@ class Core {
271
309
  return await this.client.fetch(`/triggers/open`, {
272
310
  method: "POST",
273
311
  headers,
274
- body
312
+ body: this.withClientId(body)
275
313
  });
276
314
  },
277
315
  close: async (body, headers) => {
278
316
  return await this.client.fetch(`/triggers/close`, {
279
317
  method: "POST",
280
318
  headers,
281
- body
319
+ body: this.withClientId(body)
282
320
  });
283
321
  },
284
322
  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.0.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.0.0",
29
+ "@pear-protocol/utils": "^0.0.23",
30
30
  "qs": "^6.14.0"
31
31
  },
32
32
  "devDependencies": {