🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@pear-protocol/core-sdk

Package Overview
Dependencies
Maintainers
4
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pear-protocol/core-sdk - npm Package Compare versions

Comparing version
0.1.0
to
1.0.0
+17
dist/external/index.d.ts
import { SearchTriggersParams, SearchTriggersResponse } from '@pear-protocol/types';
export { ExternalTrigger, ExternalTriggerSource, SearchTriggersParams, SearchTriggersResponse, TriggerOutcome } from '@pear-protocol/types';
declare class External {
triggers: {
kalshi: {
marketNames: (tickers: string[]) => Promise<Map<string, string>>;
search: (params?: SearchTriggersParams) => Promise<SearchTriggersResponse>;
};
polymarket: {
marketNames: (ids: string[]) => Promise<Map<string, string>>;
search: (params?: SearchTriggersParams) => Promise<SearchTriggersResponse>;
};
};
}
export { External };
import { searchKalshiTriggers, fetchKalshiMarketNames } from './kalshi';
import { searchPolymarketTriggers, fetchPolymarketMarketNames } from './polymarket';
class External {
triggers = {
kalshi: {
marketNames: async (tickers) => {
return fetchKalshiMarketNames(tickers);
},
search: async (params = {}) => {
return searchKalshiTriggers(params);
}
},
polymarket: {
marketNames: async (ids) => {
return fetchPolymarketMarketNames(ids);
},
search: async (params = {}) => {
return searchPolymarketTriggers(params);
}
}
};
}
export { External };
import { SearchTriggersParams, SearchTriggersResponse } from '@pear-protocol/types';
declare function fetchKalshiMarketNames(tickers: string[]): Promise<Map<string, string>>;
declare function searchKalshiTriggers(params?: SearchTriggersParams): Promise<SearchTriggersResponse>;
export { fetchKalshiMarketNames, searchKalshiTriggers };
const BASE_URL = "https://api.elections.kalshi.com";
const BATCH_SIZE = 100;
async function fetchKalshiMarketNames(tickers) {
const result = /* @__PURE__ */ new Map();
for (let i = 0; i < tickers.length; i += BATCH_SIZE) {
const batch = tickers.slice(i, i + BATCH_SIZE);
const url = new URL(`${BASE_URL}/trade-api/v2/markets`);
url.searchParams.set("tickers", batch.join(","));
url.searchParams.set("limit", String(BATCH_SIZE));
const response = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
if (!response.ok) throw new Error(`Kalshi API error: ${response.status} ${response.statusText}`);
const data = await response.json();
for (const m of data.markets ?? []) result.set(m.ticker, m.title);
}
return result;
}
async function searchKalshiTriggers(params = {}) {
const url = new URL(`${BASE_URL}/v1/search/series`);
url.searchParams.set("order_by", "trending");
url.searchParams.set("status", "open");
url.searchParams.set("page_size", String(params.pageSize ?? 50));
if (params.category) url.searchParams.set("category", params.category);
if (params.search) url.searchParams.set("query", params.search);
if (params.cursor) url.searchParams.set("cursor", params.cursor);
const response = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
if (!response.ok) return { triggers: [], nextCursor: null };
const data = await response.json();
return {
triggers: (data.current_page ?? []).map(mapEventToTrigger),
nextCursor: data.next_cursor || null
};
}
function mapEventToTrigger(event) {
const imageUrl = `https://kalshi-public-docs.s3.amazonaws.com/series-images-webp/${event.event_ticker.split("-")[0]}.webp`;
if (event.markets.length > 1) {
return {
id: event.event_ticker,
category: "prediction_market",
source: "kalshi",
selectable: false,
oracle: null,
options: event.markets.map(mapMarketToOutcome),
type: "multi",
title: event.event_title,
imageUrl
};
}
const market = event.markets[0];
return {
id: market?.ticker ?? event.event_ticker,
category: "prediction_market",
source: "kalshi",
selectable: true,
oracle: market?.last_price ?? null,
options: [],
type: "binary",
title: event.event_title,
imageUrl
};
}
function mapMarketToOutcome(market) {
return {
id: market.ticker,
label: market.yes_subtitle || market.title,
oracle: market.last_price
};
}
export { fetchKalshiMarketNames, searchKalshiTriggers };
import { SearchTriggersParams, SearchTriggersResponse } from '@pear-protocol/types';
declare function fetchPolymarketMarketNames(ids: string[]): Promise<Map<string, string>>;
declare function searchPolymarketTriggers(params?: SearchTriggersParams): Promise<SearchTriggersResponse>;
export { fetchPolymarketMarketNames, searchPolymarketTriggers };
const BASE_URL = "https://gamma-api.polymarket.com";
const BATCH_SIZE = 100;
async function fetchPolymarketMarketNames(ids) {
const result = /* @__PURE__ */ new Map();
for (let i = 0; i < ids.length; i += BATCH_SIZE) {
const batch = ids.slice(i, i + BATCH_SIZE);
const url = new URL(`${BASE_URL}/markets`);
for (const id of batch) url.searchParams.append("id", id);
url.searchParams.set("limit", String(BATCH_SIZE));
const response = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
if (!response.ok) throw new Error(`Polymarket API error: ${response.status} ${response.statusText}`);
const data = await response.json();
for (const m of data) result.set(m.id, m.question ?? m.groupItemTitle ?? "");
}
return result;
}
async function searchPolymarketTriggers(params = {}) {
const url = new URL(`${BASE_URL}/events/keyset`);
url.searchParams.set("closed", "false");
url.searchParams.set("limit", String(params.pageSize ?? 50));
url.searchParams.set("order", "volume24hr");
url.searchParams.set("ascending", "false");
if (params.search) url.searchParams.set("title_search", params.search);
if (params.category) url.searchParams.set("tag_slug", params.category);
if (params.cursor) url.searchParams.set("after_cursor", params.cursor);
const response = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
if (!response.ok) return { triggers: [], nextCursor: null };
const data = await response.json();
const events = data.events ?? [];
return {
triggers: events.map(mapEventToTrigger).filter((t) => t !== null),
nextCursor: data.next_cursor ?? null
};
}
function mapEventToTrigger(event) {
const markets = (event.markets ?? []).filter((m) => m.active !== false && m.closed !== true);
const [first] = markets;
if (!first) return null;
if (markets.length === 1) {
return {
id: first.id,
category: "prediction_market",
source: "polymarket",
selectable: true,
oracle: parseYesCents(first),
options: [],
type: "binary",
title: first.question ?? event.title ?? first.groupItemTitle ?? first.id,
imageUrl: first.image ?? first.icon ?? event.image ?? event.icon ?? null
};
}
return {
id: event.id ?? event.slug ?? first.id,
category: "prediction_market",
source: "polymarket",
selectable: false,
oracle: null,
options: markets.map(mapMarketToOutcome),
type: "multi",
title: event.title ?? first.question ?? event.id,
imageUrl: event.image ?? event.icon ?? first.image ?? first.icon ?? null
};
}
function mapMarketToOutcome(market) {
return {
id: market.id,
label: market.groupItemTitle ?? market.question ?? market.id,
oracle: parseYesCents(market)
};
}
function parseYesCents(market) {
const outcomes = parseStringArray(market.outcomes);
const prices = parseStringArray(market.outcomePrices);
const yesIndex = outcomes.findIndex((o) => o.toLowerCase() === "yes");
if (yesIndex < 0) return null;
const price = Number(prices[yesIndex] ?? "");
if (!Number.isFinite(price)) return null;
return Math.round(price * 1e4) / 100;
}
function parseStringArray(value) {
if (Array.isArray(value)) return value.map(String);
if (!value) return [];
try {
const parsed = JSON.parse(value);
return Array.isArray(parsed) ? parsed.map(String) : [];
} catch {
return [];
}
}
export { fetchPolymarketMarketNames, searchPolymarketTriggers };
export { ExternalTrigger, ExternalTriggerSource, SearchTriggersParams, SearchTriggersResponse, TriggerOutcome } from '@pear-protocol/types';
type KalshiMarket = {
ticker: string;
title: string;
};
type KalshiMarketsResponse = {
markets: KalshiMarket[];
};
type KalshiSearchSeriesMarket = {
ticker: string;
yes_subtitle: string;
last_price: number;
title: string;
};
type KalshiSearchSeriesEvent = {
event_ticker: string;
event_title: string;
markets: KalshiSearchSeriesMarket[];
};
type KalshiSearchSeriesResponse = {
current_page: KalshiSearchSeriesEvent[];
next_cursor: string;
};
type PolymarketMarket = {
id: string;
question?: string;
image?: string;
icon?: string;
active?: boolean;
closed?: boolean;
groupItemTitle?: string;
outcomes?: string[] | string;
outcomePrices?: string[] | string;
};
type PolymarketEvent = {
id: string;
slug?: string;
title?: string;
image?: string;
icon?: string;
markets?: PolymarketMarket[];
};
type PolymarketKeysetEventsResponse = {
events?: PolymarketEvent[];
next_cursor?: string | null;
};
export type { KalshiMarket, KalshiMarketsResponse, KalshiSearchSeriesEvent, KalshiSearchSeriesMarket, KalshiSearchSeriesResponse, PolymarketEvent, PolymarketKeysetEventsResponse, PolymarketMarket };
+6
-0

@@ -33,2 +33,8 @@ import { HttpTypes } from '@pear-protocol/types';

}>;
apiKeyMe(headers?: ClientHeaders): Promise<{
id: string;
role: "basic" | "pro" | "admin";
scope: "read" | "read_write";
authMethod: "api_key";
}>;
refreshSession(headers?: ClientHeaders): Promise<void>;

@@ -35,0 +41,0 @@ refreshToken(body: HttpTypes.RefreshTokenRequest, headers?: ClientHeaders): Promise<{

@@ -53,2 +53,9 @@ class Auth {

}
// Resolve the identity behind an API key (x-api-key auth). Session-less counterpart to `me`.
async apiKeyMe(headers) {
return await this.client.fetch(`/auth/api-key/me`, {
method: "GET",
headers
});
}
async refreshSession(headers) {

@@ -55,0 +62,0 @@ return await this.client.fetch(`/auth/session/refresh`, {

+48
-10
class Core {
client;
constructor(client) {
clientId;
constructor(client, clientId) {
this.client = client;
this.clientId = clientId;
}
// Auto-attach the configured attribution clientId to a request body unless the
// caller already set one explicitly. Bound to the exact trade / trigger / schedule /
// rebalance payloads it serves, so an unrelated body is a compile error.
withClientId(body) {
if (!this.clientId) return body;
return { clientId: this.clientId, ...body };
}
accounts = {

@@ -36,3 +45,3 @@ list: async (query, headers) => {

return await this.client.fetch(`/trade-accounts/${id}/credentials`, {
method: "GET",
method: "POST",
headers

@@ -48,2 +57,23 @@ });

};
apiKeys = {
list: async (headers) => {
return await this.client.fetch(`/api-keys`, {
method: "GET",
headers
});
},
create: async (body, headers) => {
return await this.client.fetch(`/api-keys`, {
method: "POST",
headers,
body
});
},
revoke: async (id, headers) => {
return await this.client.fetch(`/api-keys/${id}`, {
method: "DELETE",
headers
});
}
};
executions = {

@@ -120,2 +150,10 @@ list: async (query, headers) => {

};
oracle = {
btcdom: async (headers) => {
return await this.client.fetch(`/oracle/btcdom`, {
method: "GET",
headers
});
}
};
positions = {

@@ -166,3 +204,3 @@ list: async (query, headers) => {

headers,
body
body: this.withClientId(body)
});

@@ -183,3 +221,3 @@ }

headers,
body
body: this.withClientId(body)
});

@@ -235,3 +273,3 @@ },

headers,
body
body: this.withClientId(body)
});

@@ -243,3 +281,3 @@ },

headers,
body
body: this.withClientId(body)
});

@@ -251,3 +289,3 @@ },

headers,
body
body: this.withClientId(body)
});

@@ -259,3 +297,3 @@ },

headers,
body
body: this.withClientId(body)
});

@@ -283,3 +321,3 @@ },

headers,
body
body: this.withClientId(body)
});

@@ -291,3 +329,3 @@ },

headers,
body
body: this.withClientId(body)
});

@@ -294,0 +332,0 @@ },

import { AuthMode, Logger, RequestMiddleware, ResponseMiddleware, FetchInput, FetchArgs } from './types.js';
import '@pear-protocol/types';

@@ -3,0 +4,0 @@ declare class HttpClient {

+4
-2
import { Admin } from './admin/index.js';
import { Auth } from './auth/index.js';
import { Core } from './core/index.js';
import { External } from './external/index.js';
import { SDKConfig } from './types.js';
export { HttpTypes } from '@pear-protocol/types';
export { ExternalTrigger, ExternalTriggerSource, HttpTypes, SearchTriggersParams, SearchTriggersResponse, TriggerOutcome } from '@pear-protocol/types';
export * from '@pear-protocol/utils';

@@ -13,5 +14,6 @@ import './http.js';

core: Core;
external: External;
constructor(config: SDKConfig);
}
export { PearSDK as default };
export { External, PearSDK as default };
import { Admin } from './admin';
import { Auth } from './auth';
import { Core } from './core';
import { External } from './external';
export { External } from './external';
import { HttpClient } from './http';

@@ -12,2 +14,3 @@ import { FetchError } from './utils';

core;
external;
constructor(config) {

@@ -26,2 +29,3 @@ const authMode = config.auth?.type ?? "session";

this.core = new Core(client);
this.external = new External();
if (authMode === "session") {

@@ -78,2 +82,22 @@ let refreshInFlight = null;

}
if (authMode === "apikey" && config.auth?.key) {
const getKey = config.auth.key;
client.useRequest(async (request, next) => {
const key = getKey();
if (key) {
request.headers.set("x-api-key", key);
}
return next();
});
if (config.onAuthError) {
const onAuthError = config.onAuthError;
client.useResponse(async (response) => {
if (response.status === 401) {
onAuthError();
throw new FetchError("Unauthorized. API key may be expired or revoked.", "Unauthorized", 401);
}
return response;
});
}
}
if (config.getTradeAccountId) {

@@ -80,0 +104,0 @@ const getTradeAccountId = config.getTradeAccountId;

@@ -1,2 +0,4 @@

type AuthMode = 'session' | 'bearer';
import { HttpTypes } from '@pear-protocol/types';
type AuthMode = 'session' | 'bearer' | 'apikey';
type SDKConfig = {

@@ -19,4 +21,9 @@ /**

* Token set on every request via `Authorization` header. Provide
* `token` getter to supply the API key or JWT. No client-side refresh.
* If 401, caller handles re-auth. Used by headless / API-key clients.
* `token` getter to supply the JWT. No client-side refresh.
* If 401, caller handles re-auth. Used by headless JWT clients.
*
* Apikey:
* API key sent on every request via the `x-api-key` header. Provide
* `key` getter. No cookies, no client-side refresh. If 401, caller
* handles re-auth. Used by programmatic API-key clients.
*/

@@ -26,7 +33,13 @@ auth?: {

/**
* Token getter for bearer mode (e.g. () => apiKey). Ignored in session mode.
* Token getter for bearer mode (e.g. () => jwt). Ignored in other modes.
*
* Example: () => localStorage.getItem('accessToken')
*/
token?: () => string | null;
/**
* API key getter for apikey mode. Ignored in other modes.
*
* Example: () => localStorage.getItem('apiKey')
*/
token?: () => string | null;
key?: () => string | null;
};

@@ -40,4 +53,13 @@ /**

/**
* Called when server returns 401 (bearer mode only).
* Default attribution client code (client_ids.code). When set, it is
* auto-added to the body of trade / trigger / schedule / rebalance requests
* unless the call already specifies its own `clientId`. `null`/omitted →
* nothing is added.
*
* Example: 'AGENTPEAR'
*/
clientId?: string | null;
/**
* Called when server returns 401 (bearer / apikey mode).
*
* Example: () => {

@@ -95,3 +117,4 @@ * console.error('Unauthorized. Token may be expired or revoked.');

type ResponseMiddleware = (response: Response, retry: () => Promise<Response>, request: Request) => Promise<Response>;
type ClientIdBody = HttpTypes.RebalanceManually | HttpTypes.CreateSchedule | HttpTypes.CreateTradeOpen | HttpTypes.CreateTradeAdjust | HttpTypes.CreateTradeClose | HttpTypes.CreateTradeCloseAll | HttpTypes.CreateTriggerOpen | HttpTypes.CreateTriggerClose;
export type { AuthMode, ClientHeaders, FetchArgs, FetchInput, FetchParams, Logger, RequestMiddleware, ResponseMiddleware, SDKConfig };
export type { AuthMode, ClientHeaders, ClientIdBody, FetchArgs, FetchInput, FetchParams, Logger, RequestMiddleware, ResponseMiddleware, SDKConfig };
import { FetchArgs, AuthMode } from './types.js';
import '@pear-protocol/types';

@@ -3,0 +4,0 @@ declare function getBaseUrl(passedBaseUrl: string): string;

{
"name": "@pear-protocol/core-sdk",
"version": "0.1.0",
"version": "1.0.0",
"description": "Pear Protocol Core SDK",

@@ -28,4 +28,4 @@ "private": false,

"dependencies": {
"@pear-protocol/types": "^0.1.0",
"@pear-protocol/utils": "^0.0.22",
"@pear-protocol/types": "^1.0.0",
"@pear-protocol/utils": "^0.0.23",
"qs": "^6.14.0"

@@ -32,0 +32,0 @@ },

Sorry, the diff of this file is too big to display