@pear-protocol/utils
Advanced tools
| /** | ||
| * Optional forward-proxy for outbound SDK HTTP calls. | ||
| * | ||
| * When enabled, every request is re-pointed at the proxy's origin with the original destination | ||
| * carried in the `X-Proxy-Target` header. The proxy restores method, path, query, body, and headers | ||
| * before forwarding upstream (see pear-proxy). Off by default — a transparent passthrough to the | ||
| * global `fetch`. | ||
| * | ||
| * Config is INJECTED by the caller via the SDK constructors (`configureProxy`), never read from the | ||
| * environment: the SDKs also run in the browser, where `process.env` does not exist. | ||
| * | ||
| * Fallback: the proxy is best-effort. If the proxied call fails for any reason other than a genuine | ||
| * 4xx response — a network/transport error, or a proxy-side 5xx such as the load-shed 503 or the | ||
| * request-timeout 504 — the request is retried once directly against the original target, un-proxied. | ||
| * A 4xx passes straight through, since that is the upstream's own answer and a direct retry would | ||
| * only repeat it. | ||
| */ | ||
| export type ProxyConfig = { | ||
| /** Master switch. When false (or the URL is missing), `proxyFetch` is a transparent passthrough. */ | ||
| enabled: boolean; | ||
| /** Proxy base URL; only its origin (scheme + host + port) is used. */ | ||
| url?: string; | ||
| }; | ||
| /** | ||
| * Set (or clear) the forward-proxy used by every `proxyFetch` call. Called from the SDK | ||
| * constructors with the caller-supplied config. Passing a disabled/absent config turns it off. | ||
| */ | ||
| export declare function configureProxy(config: ProxyConfig | null | undefined): void; | ||
| /** | ||
| * `fetch` for a string/URL request that routes through the configured proxy when enabled (with a | ||
| * direct-call fallback); otherwise calls the global `fetch` unchanged. All SDK call sites pass a | ||
| * URL + init, so a `Request`-object input is intentionally not supported. | ||
| */ | ||
| export declare function proxyFetch(input: string | URL, init?: RequestInit): Promise<Response>; |
| export {}; |
+1
-0
@@ -9,4 +9,5 @@ export * from './asset/index'; | ||
| export * from './precise-quantity'; | ||
| export * from './proxy'; | ||
| export * from './sync/index'; | ||
| export * from './validate-leverage'; | ||
| export * from './validate-quantity'; |
+71
-1
@@ -414,2 +414,33 @@ import BigNumber9 from 'bignumber.js'; | ||
| } | ||
| function computePositionEntryPrices(exposureMap, fills) { | ||
| const entryPrices = {}; | ||
| for (const instrumentId of Object.keys(exposureMap)) { | ||
| const assetFills = fills.filter((fill) => fill.symbol === instrumentId); | ||
| const entryPrice = computeEntryPriceForAsset(assetFills); | ||
| if (isZero(entryPrice)) continue; | ||
| entryPrices[instrumentId] = entryPrice.toFixed(); | ||
| } | ||
| return entryPrices; | ||
| } | ||
| function computeUnrealizedPositionStateFromEntryPrices(exposureMap, entryPrices, priceMap) { | ||
| const assetUPnLs = []; | ||
| for (const [id, signedQuantityString] of Object.entries(exposureMap)) { | ||
| const currentPriceString = priceMap[id]; | ||
| const entryPriceString = entryPrices[id]; | ||
| if (!currentPriceString || !entryPriceString) continue; | ||
| const signedQuantity = parse(signedQuantityString); | ||
| if (isZero(signedQuantity)) continue; | ||
| const currentPrice = parse(currentPriceString); | ||
| const entryPrice2 = parse(entryPriceString); | ||
| const upnl2 = multiply(signedQuantity, subtract(currentPrice, entryPrice2)); | ||
| assetUPnLs.push({ id, signedQuantity, entryPrice: entryPrice2, currentPrice, upnl: upnl2 }); | ||
| } | ||
| const entryPrice = computePositionEntryPrice(assetUPnLs); | ||
| const entryNotional = computePositionEntryNotional(assetUPnLs); | ||
| const markPrice = computePositionCurrentPrice(assetUPnLs); | ||
| const markNotional = computePositionMarkNotional(assetUPnLs); | ||
| const upnl = computePositionUnrealizedPnL(assetUPnLs); | ||
| const upnlBips = computePositionUnrealizedPnLBips(upnl, entryNotional); | ||
| return { assetUPnLs, entryPrice, entryNotional, markPrice, markNotional, upnl, upnlBips }; | ||
| } | ||
| function generateDeterministicPositionKey(input) { | ||
@@ -516,2 +547,41 @@ const symbols = [...input.symbols].sort((a, b) => a.localeCompare(b)); | ||
| // src/proxy.ts | ||
| var activeOrigin = null; | ||
| function configureProxy(config) { | ||
| if (!config?.enabled || !config.url) { | ||
| activeOrigin = null; | ||
| return; | ||
| } | ||
| try { | ||
| activeOrigin = new URL(config.url).origin; | ||
| } catch { | ||
| activeOrigin = null; | ||
| } | ||
| } | ||
| function toProxyUrl(target, origin) { | ||
| const proxied = new URL(origin); | ||
| proxied.pathname = target.pathname; | ||
| proxied.search = target.search; | ||
| return proxied.toString(); | ||
| } | ||
| async function withProxyFallback(proxied, direct) { | ||
| try { | ||
| const response = await proxied(); | ||
| if (response.status < 500) return response; | ||
| } catch { | ||
| } | ||
| return direct(); | ||
| } | ||
| function proxyFetch(input, init) { | ||
| const origin = activeOrigin; | ||
| if (!origin) return fetch(input, init); | ||
| const target = new URL(input); | ||
| const headers = new Headers(init?.headers); | ||
| headers.set("X-Proxy-Target", target.host); | ||
| return withProxyFallback( | ||
| () => fetch(toProxyUrl(target, origin), { ...init, headers }), | ||
| () => fetch(input, init) | ||
| ); | ||
| } | ||
| // src/sync/applicables/constants.ts | ||
@@ -1682,2 +1752,2 @@ var DUST = parse("0.00000001"); | ||
| export { BIPS, ZERO, abs, add, baseToContracts, compareValue, computeAssetEntryNotional, computeAssetGrossRealizedPnL, computeAssetRealizedPnLs, computeAssetUndeterminedSizes, computeAssetUnrealizedPnL, computeAssetUnrealizedPnLs, computeBasketWeightedRatioV1, computeEntryPriceForAsset, computeRealizedPnlBySymbol, computeRealizedPnlFromFills, computeRealizedPositionState, computeSyncPayload, computeUnrealizedPositionState, contractsToBase, countDecimals, divide, exponentiate, generateDeterministicPositionKey, isEqualTo, isFiniteDecimal, isGreaterThan, isGreaterThanOrEqual, isLessThan, isLessThanOrEqual, isNegative, isPositive, isZero, min, multiply, negate, parse, precisePrice, preciseQuantity, sideSign, sign, signed, signedBySide, subtract, toDecimalString, validateLeverage, validateQuantity }; | ||
| export { BIPS, ZERO, abs, add, baseToContracts, compareValue, computeAssetEntryNotional, computeAssetGrossRealizedPnL, computeAssetRealizedPnLs, computeAssetUndeterminedSizes, computeAssetUnrealizedPnL, computeAssetUnrealizedPnLs, computeBasketWeightedRatioV1, computeEntryPriceForAsset, computePositionEntryPrices, computeRealizedPnlBySymbol, computeRealizedPnlFromFills, computeRealizedPositionState, computeSyncPayload, computeUnrealizedPositionState, computeUnrealizedPositionStateFromEntryPrices, configureProxy, contractsToBase, countDecimals, divide, exponentiate, generateDeterministicPositionKey, isEqualTo, isFiniteDecimal, isGreaterThan, isGreaterThanOrEqual, isLessThan, isLessThanOrEqual, isNegative, isPositive, isZero, min, multiply, negate, parse, precisePrice, preciseQuantity, proxyFetch, sideSign, sign, signed, signedBySide, subtract, toDecimalString, validateLeverage, validateQuantity }; |
@@ -22,2 +22,18 @@ import type { InstrumentId } from '@pear-protocol/types'; | ||
| export declare function computeRealizedPositionState(fills: Fill[]): RealizedPositionState; | ||
| /** | ||
| * Weighted-average entry (cost-basis) price per instrument in a position, derived purely from | ||
| * fills — no mark price needed. This is the authoritative source for a position's entry price; | ||
| * callers that already have it (e.g. from a position API response) should NOT re-derive it a | ||
| * second time by replaying fills themselves. | ||
| * | ||
| * Formula (per instrument): cost-basis average via computeEntryPriceForAsset. | ||
| */ | ||
| export declare function computePositionEntryPrices(exposureMap: ExposureMap, fills: Fill[]): Record<InstrumentId, string>; | ||
| /** | ||
| * Unrealized position state derived from ALREADY-KNOWN entry prices (e.g. the entryPrices field | ||
| * on a position API response) instead of replaying the fills ledger. Prefer this over | ||
| * computeUnrealizedPositionState whenever the caller already has entry prices — it needs no | ||
| * fills fetch at all, only a live mark-price map. | ||
| */ | ||
| export declare function computeUnrealizedPositionStateFromEntryPrices(exposureMap: ExposureMap, entryPrices: Record<InstrumentId, string>, priceMap: PriceMap): UnrealizedPositionState; | ||
| export {}; |
+2
-2
| { | ||
| "name": "@pear-protocol/utils", | ||
| "version": "0.1.0", | ||
| "version": "0.2.0", | ||
| "description": "Pear Protocol Utility functions", | ||
@@ -30,3 +30,3 @@ "private": false, | ||
| "@noble/hashes": "^1.3.2", | ||
| "@pear-protocol/types": "^1.6.0", | ||
| "@pear-protocol/types": "^1.9.0", | ||
| "bignumber.js": "9.3.1" | ||
@@ -33,0 +33,0 @@ }, |
Network access
Supply chain riskThis module accesses the network.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
98421
6.14%53
3.92%2578
4.97%3
200%Updated