@vesper85/strategy-sdk 0.1.2 → 0.1.4

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/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import { createClient } from 'redis';
9
9
  import superjson from 'superjson';
10
10
  import { TechnicalAnalysisService } from '@osiris-ai/technical-indicators';
11
11
  import WebSocket from 'ws';
12
+ import { RealTimeDataClient, ConnectionStatus } from '@polymarket/real-time-data-client';
12
13
  import { privateKeyToAccount } from 'viem/accounts';
13
14
  import { sepolia, base, optimism, arbitrum, polygon, mainnet } from 'viem/chains';
14
15
 
@@ -27,6 +28,30 @@ function isOpportunitySubscription(sub) {
27
28
  function isCustomSubscription(sub) {
28
29
  return sub.type === "custom";
29
30
  }
31
+ function isClobMarketSubscription(sub) {
32
+ return sub.type === "clob_market";
33
+ }
34
+ function isClobUserSubscription(sub) {
35
+ return sub.type === "clob_user";
36
+ }
37
+ function isActivitySubscription(sub) {
38
+ return sub.type === "activity";
39
+ }
40
+ function isCommentsSubscription(sub) {
41
+ return sub.type === "comments";
42
+ }
43
+ function isCryptoPricesSubscription(sub) {
44
+ return sub.type === "crypto_prices";
45
+ }
46
+ function isRfqSubscription(sub) {
47
+ return sub.type === "rfq";
48
+ }
49
+ function isPolymarketSubscription(sub) {
50
+ return isClobMarketSubscription(sub) || isClobUserSubscription(sub) || isActivitySubscription(sub) || isCommentsSubscription(sub) || isCryptoPricesSubscription(sub) || isRfqSubscription(sub);
51
+ }
52
+ function isOsirisSubscription(sub) {
53
+ return isWalletSubscription(sub) || isOpportunitySubscription(sub);
54
+ }
30
55
  var OsirisSigner = class {
31
56
  hubBaseUrl;
32
57
  accessToken;
@@ -161,6 +186,80 @@ var OsirisSigner = class {
161
186
  return void 0;
162
187
  }
163
188
  };
189
+
190
+ // src/utils/index.ts
191
+ function mapToGammaMarket(raw) {
192
+ const safeParse = (value) => {
193
+ try {
194
+ return typeof value === "string" ? JSON.parse(value) : value;
195
+ } catch {
196
+ return [];
197
+ }
198
+ };
199
+ return {
200
+ // Identity & Basic Info
201
+ id: raw.id,
202
+ question: raw.question,
203
+ slug: raw.slug,
204
+ condition_id: raw.conditionId,
205
+ question_id: raw.questionId,
206
+ // If present
207
+ description: raw.description,
208
+ // Dates
209
+ end_date: raw.endDate,
210
+ start_date: raw.startDate,
211
+ created_at: raw.createdAt,
212
+ updated_at: raw.updatedAt,
213
+ closed_time: raw.closedTime,
214
+ // Images
215
+ image: raw.image,
216
+ icon: raw.icon,
217
+ twitter_card_image: raw.twitterCardImage,
218
+ // Categorization
219
+ category: raw.category,
220
+ tags: raw.tags,
221
+ market_type: raw.marketType,
222
+ active: raw.active,
223
+ closed: raw.closed,
224
+ archived: raw.archived,
225
+ restricted: raw.restricted,
226
+ // Financials & Numbers (Type Conversions)
227
+ liquidity: raw.liquidity ? parseFloat(raw.liquidity) : 0,
228
+ volume: raw.volume,
229
+ // Interface keeps this as string
230
+ volume_24hr: raw.volume24hr?.toString(),
231
+ // Prices (Number -> String conversion based on your Interface)
232
+ best_bid: raw.bestBid?.toString(),
233
+ best_ask: raw.bestAsk?.toString(),
234
+ last_trade_price: raw.lastTradePrice?.toString(),
235
+ // Arrays (Parsing stringified JSON)
236
+ outcomes: safeParse(raw.outcomes),
237
+ outcome_prices: safeParse(raw.outcomePrices),
238
+ outcomePrices: safeParse(raw.outcomePrices),
239
+ // Populating alias
240
+ clob_token_ids: safeParse(raw.clobTokenIds),
241
+ clobTokenIds: safeParse(raw.clobTokenIds),
242
+ // Populating alias
243
+ uma_resolution_statuses: safeParse(raw.umaResolutionStatuses),
244
+ // Market Maker & Fees
245
+ market_maker_address: raw.marketMakerAddress,
246
+ maker_fee_bps: raw.makerFeeBps,
247
+ taker_fee_bps: raw.takerFeeBps,
248
+ // IDs
249
+ created_by: raw.updatedBy,
250
+ // Note: response has updatedBy, mapping to potentially relevant field
251
+ updated_by: raw.updatedBy,
252
+ // Misc
253
+ events: raw.events,
254
+ // Pass through if structure matches, otherwise map Event type similarly
255
+ new: raw.new,
256
+ featured: raw.featured,
257
+ cyom: raw.cyom,
258
+ competitive: raw.competitive
259
+ };
260
+ }
261
+
262
+ // src/clients/polymarket-client.ts
164
263
  var MaxUint256BigInt = typeof ethers.constants !== "undefined" && ethers.constants.MaxUint256 ? BigInt(ethers.MaxUint256.toString()) : BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
165
264
  var POLYGON_CHAIN_ID = 137;
166
265
  var USDC_ADDRESS = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
@@ -178,6 +277,13 @@ var ERC1155_ABI = [
178
277
  "function setApprovalForAll(address operator, bool approved) external",
179
278
  "function isApprovedForAll(address account, address operator) external view returns (bool)"
180
279
  ];
280
+ function wrapWalletForV5Compatibility(wallet) {
281
+ const wrappedWallet = wallet;
282
+ wrappedWallet._signTypedData = async function(domain, types, value) {
283
+ return wallet.signTypedData(domain, types, value);
284
+ };
285
+ return wrappedWallet;
286
+ }
181
287
  var PolymarketClient = class {
182
288
  constructor(logger, signer, userAddress, options) {
183
289
  this.logger = logger;
@@ -185,7 +291,7 @@ var PolymarketClient = class {
185
291
  this.userAddress = userAddress;
186
292
  this.gammaClient = new PolymarketGammaClient();
187
293
  this.provider = new ethers.JsonRpcProvider(POLYGON_RPC_URL);
188
- this.isOsirisSigner = signer instanceof OsirisSigner || signer.impl instanceof OsirisSigner || signer.getPrivateKey() === void 0;
294
+ this.isOsirisSigner = signer instanceof OsirisSigner || signer.getPrivateKey() === void 0;
189
295
  this.options = {
190
296
  chainId: options?.chainId ?? POLYGON_CHAIN_ID,
191
297
  autoApprove: options?.autoApprove ?? false,
@@ -244,10 +350,11 @@ var PolymarketClient = class {
244
350
  throw new Error("Could not obtain private key for CLOB client initialization. Private key signer is required for trading.");
245
351
  }
246
352
  this.wallet = new ethers.Wallet(privateKey, this.provider);
353
+ const v5CompatibleWallet = wrapWalletForV5Compatibility(this.wallet);
247
354
  const tempClient = new ClobClient(
248
355
  this.options.clobHost,
249
356
  this.options.chainId,
250
- this.wallet
357
+ v5CompatibleWallet
251
358
  );
252
359
  this.logger.info("Deriving API credentials...");
253
360
  const apiCreds = await tempClient.createOrDeriveApiKey();
@@ -255,7 +362,7 @@ var PolymarketClient = class {
255
362
  this.clobClient = new ClobClient(
256
363
  this.options.clobHost,
257
364
  this.options.chainId,
258
- this.wallet,
365
+ v5CompatibleWallet,
259
366
  apiCreds,
260
367
  signatureType
261
368
  );
@@ -269,15 +376,6 @@ var PolymarketClient = class {
269
376
  isTradingClientInitialized() {
270
377
  return this.tradingInitialized;
271
378
  }
272
- async getPrivateKeyFromSigner() {
273
- if (this.signer && "getPrivateKey" in this.signer) {
274
- return this.signer.getPrivateKey();
275
- }
276
- if (this.signer && this.signer.account?.privateKey) {
277
- return this.signer.account.privateKey;
278
- }
279
- return null;
280
- }
281
379
  ensureTradingClient() {
282
380
  if (!this.clobClient || !this.tradingInitialized) {
283
381
  throw new Error("Trading client not initialized. Call initializeTradingClient() first.");
@@ -1099,7 +1197,8 @@ var PolymarketClient = class {
1099
1197
  throw new Error(`Gamma API error: ${response.status} ${response.statusText}`);
1100
1198
  }
1101
1199
  const data = await response.json();
1102
- return data;
1200
+ const mappedData = data.map(mapToGammaMarket);
1201
+ return mappedData;
1103
1202
  } catch (error) {
1104
1203
  this.logger.error("Error fetching markets from Gamma API", error);
1105
1204
  throw error;
@@ -1596,11 +1695,11 @@ async function runStrategy(strategy, config, context) {
1596
1695
  }
1597
1696
  return false;
1598
1697
  } catch (error) {
1599
- config.logger.error(`Error executing strategy: ${error.message}`, error);
1698
+ config.logger?.error(`Error executing strategy: ${error.message}`, error);
1600
1699
  throw error;
1601
1700
  }
1602
1701
  }
1603
- function createStrategyEngine(strategy, config, context) {
1702
+ function createStrategyEngine(strategy, context, config) {
1604
1703
  return new StrategyEngine(strategy, config, context);
1605
1704
  }
1606
1705
  var StrategyEngine = class {
@@ -1608,6 +1707,7 @@ var StrategyEngine = class {
1608
1707
  this.strategy = strategy;
1609
1708
  this.config = config;
1610
1709
  this.context = context;
1710
+ this.config.logger = this.config.logger || createConsoleLogger();
1611
1711
  }
1612
1712
  intervalId = null;
1613
1713
  isRunning = false;
@@ -1615,6 +1715,9 @@ var StrategyEngine = class {
1615
1715
  * Start the engine with the configured tick interval
1616
1716
  */
1617
1717
  start() {
1718
+ if (!this.config.logger) {
1719
+ this.config.logger = createConsoleLogger();
1720
+ }
1618
1721
  if (this.isRunning) {
1619
1722
  this.config.logger.warning("Strategy engine is already running");
1620
1723
  return;
@@ -1631,6 +1734,9 @@ var StrategyEngine = class {
1631
1734
  * Stop the engine
1632
1735
  */
1633
1736
  stop() {
1737
+ if (!this.config.logger) {
1738
+ this.config.logger = createConsoleLogger();
1739
+ }
1634
1740
  if (!this.isRunning) {
1635
1741
  return;
1636
1742
  }
@@ -1649,6 +1755,9 @@ var StrategyEngine = class {
1649
1755
  }
1650
1756
  async tick() {
1651
1757
  const tickStart = Date.now();
1758
+ if (!this.config.logger) {
1759
+ this.config.logger = createConsoleLogger();
1760
+ }
1652
1761
  this.config.logger.debug(`Tick start: ${(/* @__PURE__ */ new Date()).toISOString()}`);
1653
1762
  try {
1654
1763
  await runStrategy(this.strategy, this.config, this.context);
@@ -1862,7 +1971,59 @@ var PolymarketEventRunner = class {
1862
1971
  const rtdsSubscriptions = [];
1863
1972
  for (const sub of this.strategy.subscriptions) {
1864
1973
  let rtdsSub = null;
1865
- if (isMarketSubscription(sub)) {
1974
+ if (isCryptoPricesSubscription(sub)) {
1975
+ rtdsSub = {
1976
+ topic: "crypto_prices",
1977
+ type: "update"
1978
+ };
1979
+ if (sub.symbol) {
1980
+ rtdsSub.filters = JSON.stringify({ symbol: sub.symbol.toLowerCase() });
1981
+ }
1982
+ } else if (isActivitySubscription(sub)) {
1983
+ rtdsSub = {
1984
+ topic: "activity",
1985
+ type: sub.messageType || "*"
1986
+ };
1987
+ if (sub.eventSlug) {
1988
+ rtdsSub.filters = JSON.stringify({ event_slug: sub.eventSlug });
1989
+ } else if (sub.marketSlug) {
1990
+ rtdsSub.filters = JSON.stringify({ market_slug: sub.marketSlug });
1991
+ }
1992
+ } else if (isClobMarketSubscription(sub)) {
1993
+ rtdsSub = {
1994
+ topic: "clob_market",
1995
+ type: sub.messageType || "*",
1996
+ filters: JSON.stringify([sub.marketId])
1997
+ };
1998
+ } else if (isClobUserSubscription(sub)) {
1999
+ rtdsSub = {
2000
+ topic: "clob_user",
2001
+ type: sub.messageType || "*"
2002
+ };
2003
+ if (this.config.clobAuth) {
2004
+ rtdsSub.clob_auth = this.config.clobAuth;
2005
+ } else {
2006
+ this.config.logger.warning(
2007
+ `clob_user subscription requires clobAuth credentials`
2008
+ );
2009
+ }
2010
+ } else if (isCommentsSubscription(sub)) {
2011
+ rtdsSub = {
2012
+ topic: "comments",
2013
+ type: sub.messageType || "*"
2014
+ };
2015
+ if (sub.parentEntityId && sub.parentEntityType) {
2016
+ rtdsSub.filters = JSON.stringify({
2017
+ parentEntityID: sub.parentEntityId,
2018
+ parentEntityType: sub.parentEntityType
2019
+ });
2020
+ }
2021
+ } else if (isRfqSubscription(sub)) {
2022
+ rtdsSub = {
2023
+ topic: "rfq",
2024
+ type: sub.messageType || "*"
2025
+ };
2026
+ } else if (isMarketSubscription(sub)) {
1866
2027
  const topic = this.mapEventTypeToTopic(sub.type);
1867
2028
  rtdsSub = {
1868
2029
  topic,
@@ -1891,7 +2052,7 @@ var PolymarketEventRunner = class {
1891
2052
  }
1892
2053
  } else {
1893
2054
  this.config.logger.warning(
1894
- `Subscription type '${sub.type}' is not supported by Polymarket RTDS. Only market subscriptions (price, orderbook, trade, fill) and custom subscriptions with valid RTDS topics are supported.`
2055
+ `Subscription type '${sub.type}' is not supported by Polymarket RTDS. Osiris-only subscription types (wallet, opportunity) should use eventSource: 'osiris'.`
1895
2056
  );
1896
2057
  continue;
1897
2058
  }
@@ -1911,6 +2072,9 @@ var PolymarketEventRunner = class {
1911
2072
  /**
1912
2073
  * Get the message type for a given RTDS topic
1913
2074
  * Each topic has specific message types as per the Polymarket RTDS documentation
2075
+ *
2076
+ * Note: Only 'crypto_prices' and 'comments' are documented RTDS topics.
2077
+ * 'trades' and 'orders' subscriptions require the CLOB WebSocket API, not RTDS.
1914
2078
  */
1915
2079
  getMessageTypeForTopic(topic) {
1916
2080
  switch (topic) {
@@ -1918,15 +2082,18 @@ var PolymarketEventRunner = class {
1918
2082
  return "update";
1919
2083
  case "comments":
1920
2084
  return "comment_created";
1921
- // Subscribes to all comment events
1922
2085
  case "trades":
1923
- return "orders_matched";
2086
+ this.config.logger.warning(
2087
+ `Topic 'trades' may not be supported by Polymarket RTDS. Consider using the CLOB WebSocket API for order/trade events.`
2088
+ );
2089
+ return "trade";
1924
2090
  case "orders":
2091
+ this.config.logger.warning(
2092
+ `Topic 'orders' may not be supported by Polymarket RTDS. Consider using the CLOB WebSocket API for order/trade events.`
2093
+ );
1925
2094
  return "order_placed";
1926
- // Can also be 'order_cancelled', 'order_filled'
1927
2095
  case "activity":
1928
2096
  return "trade";
1929
- // Can also be 'offer', etc.
1930
2097
  case "profile":
1931
2098
  return "update";
1932
2099
  default:
@@ -2114,10 +2281,6 @@ var PolymarketEventRunner = class {
2114
2281
  * Dispatch an event to the strategy's onEvent handler
2115
2282
  */
2116
2283
  async dispatchEvent(event) {
2117
- const eventStart = Date.now();
2118
- this.config.logger.debug(
2119
- `Dispatching ${event.type} event${event.market ? ` for ${event.market}` : ""}`
2120
- );
2121
2284
  try {
2122
2285
  if (this.strategy.onEvent) {
2123
2286
  await this.strategy.onEvent(event, this.context);
@@ -2128,8 +2291,6 @@ var PolymarketEventRunner = class {
2128
2291
  error
2129
2292
  );
2130
2293
  }
2131
- const eventDuration = Date.now() - eventStart;
2132
- this.config.logger.debug(`Event handling completed in ${eventDuration}ms`);
2133
2294
  }
2134
2295
  };
2135
2296
  function createPolymarketEventRunner(strategy, config, context) {
@@ -2481,11 +2642,7 @@ var OsirisEventRunner = class {
2481
2642
  * Dispatch an event to the strategy's onEvent handler
2482
2643
  */
2483
2644
  async dispatchEvent(event) {
2484
- const eventStart = Date.now();
2485
- const target = event.market || event.wallet || "";
2486
- this.config.logger.debug(
2487
- `Dispatching ${event.type} event${target ? ` for ${target}` : ""}`
2488
- );
2645
+ event.market || event.wallet || "";
2489
2646
  try {
2490
2647
  if (this.strategy.onEvent) {
2491
2648
  await this.strategy.onEvent(event, this.context);
@@ -2496,8 +2653,6 @@ var OsirisEventRunner = class {
2496
2653
  error
2497
2654
  );
2498
2655
  }
2499
- const eventDuration = Date.now() - eventStart;
2500
- this.config.logger.debug(`Event handling completed in ${eventDuration}ms`);
2501
2656
  }
2502
2657
  };
2503
2658
  function createEventRunner(strategy, config, context) {
@@ -2525,6 +2680,888 @@ function createEventRunner(strategy, config, context) {
2525
2680
  if (!config.eventSourceUrl) ;
2526
2681
  return new OsirisEventRunner(strategy, config, context);
2527
2682
  }
2683
+ var PolymarketRTDSService = class {
2684
+ client = null;
2685
+ config;
2686
+ isConnected = false;
2687
+ activeSubscriptions = [];
2688
+ constructor(config) {
2689
+ this.config = config;
2690
+ }
2691
+ /**
2692
+ * Connect to the Polymarket RTDS WebSocket
2693
+ */
2694
+ connect() {
2695
+ if (this.isConnected) {
2696
+ this.config.logger.warning("PolymarketRTDS: Already connected");
2697
+ return;
2698
+ }
2699
+ this.config.logger.info("PolymarketRTDS: Connecting...");
2700
+ this.client = new RealTimeDataClient({
2701
+ onConnect: (_client) => {
2702
+ this.isConnected = true;
2703
+ this.config.logger.info("PolymarketRTDS: Connected");
2704
+ this.config.onConnect?.();
2705
+ },
2706
+ onMessage: (_client, message) => {
2707
+ this.handleMessage(message);
2708
+ },
2709
+ onStatusChange: (status) => {
2710
+ if (status === ConnectionStatus.DISCONNECTED) {
2711
+ this.isConnected = false;
2712
+ this.config.logger.info("PolymarketRTDS: Disconnected");
2713
+ this.config.onDisconnect?.();
2714
+ } else if (status === ConnectionStatus.CONNECTING) {
2715
+ this.config.logger.info("PolymarketRTDS: Reconnecting...");
2716
+ }
2717
+ },
2718
+ pingInterval: this.config.pingIntervalMs ?? 5e3,
2719
+ autoReconnect: this.config.autoReconnect ?? true
2720
+ });
2721
+ this.client.connect();
2722
+ }
2723
+ /**
2724
+ * Disconnect from the Polymarket RTDS WebSocket
2725
+ */
2726
+ disconnect() {
2727
+ if (!this.client) {
2728
+ return;
2729
+ }
2730
+ this.config.logger.info("PolymarketRTDS: Disconnecting...");
2731
+ this.client.disconnect();
2732
+ this.client = null;
2733
+ this.isConnected = false;
2734
+ this.activeSubscriptions = [];
2735
+ }
2736
+ /**
2737
+ * Check if connected
2738
+ */
2739
+ isActive() {
2740
+ return this.isConnected;
2741
+ }
2742
+ /**
2743
+ * Subscribe to events
2744
+ * Converts SDK EventSubscription types to RTDS Subscription format
2745
+ */
2746
+ subscribe(subscriptions) {
2747
+ if (!this.client) {
2748
+ this.config.logger.warning("PolymarketRTDS: Cannot subscribe - not connected");
2749
+ return;
2750
+ }
2751
+ const rtdsSubscriptions = this.mapToRTDSSubscriptions(subscriptions);
2752
+ if (rtdsSubscriptions.length === 0) {
2753
+ this.config.logger.warning("PolymarketRTDS: No valid subscriptions to add");
2754
+ return;
2755
+ }
2756
+ const msg = { subscriptions: rtdsSubscriptions };
2757
+ this.client.subscribe(msg);
2758
+ this.activeSubscriptions.push(...rtdsSubscriptions);
2759
+ this.config.logger.info(
2760
+ `PolymarketRTDS: Subscribed to ${rtdsSubscriptions.length} topic(s): ` + rtdsSubscriptions.map((s) => `${s.topic}:${s.type}`).join(", ")
2761
+ );
2762
+ }
2763
+ /**
2764
+ * Unsubscribe from events
2765
+ */
2766
+ unsubscribe(subscriptions) {
2767
+ if (!this.client) {
2768
+ return;
2769
+ }
2770
+ const rtdsSubscriptions = this.mapToRTDSSubscriptions(subscriptions);
2771
+ if (rtdsSubscriptions.length === 0) {
2772
+ return;
2773
+ }
2774
+ const msg = { subscriptions: rtdsSubscriptions };
2775
+ this.client.unsubscribe(msg);
2776
+ for (const unsub of rtdsSubscriptions) {
2777
+ const idx = this.activeSubscriptions.findIndex(
2778
+ (s) => s.topic === unsub.topic && s.type === unsub.type
2779
+ );
2780
+ if (idx >= 0) {
2781
+ this.activeSubscriptions.splice(idx, 1);
2782
+ }
2783
+ }
2784
+ this.config.logger.info(
2785
+ `PolymarketRTDS: Unsubscribed from ${rtdsSubscriptions.length} topic(s)`
2786
+ );
2787
+ }
2788
+ /**
2789
+ * Map SDK EventSubscription to RTDS Subscription format
2790
+ */
2791
+ mapToRTDSSubscriptions(subscriptions) {
2792
+ const result = [];
2793
+ for (const sub of subscriptions) {
2794
+ const rtdsSub = this.mapSubscription(sub);
2795
+ if (rtdsSub) {
2796
+ result.push(rtdsSub);
2797
+ }
2798
+ }
2799
+ return result;
2800
+ }
2801
+ /**
2802
+ * Map a single SDK EventSubscription to RTDS Subscription
2803
+ */
2804
+ mapSubscription(sub) {
2805
+ if (isClobMarketSubscription(sub)) {
2806
+ return this.mapClobMarketSubscription(sub);
2807
+ }
2808
+ if (isClobUserSubscription(sub)) {
2809
+ return this.mapClobUserSubscription(sub);
2810
+ }
2811
+ if (isActivitySubscription(sub)) {
2812
+ return this.mapActivitySubscription(sub);
2813
+ }
2814
+ if (isCommentsSubscription(sub)) {
2815
+ return this.mapCommentsSubscription(sub);
2816
+ }
2817
+ if (isCryptoPricesSubscription(sub)) {
2818
+ return this.mapCryptoPricesSubscription(sub);
2819
+ }
2820
+ if (isRfqSubscription(sub)) {
2821
+ return this.mapRfqSubscription(sub);
2822
+ }
2823
+ if (isMarketSubscription(sub)) {
2824
+ return this.mapMarketSubscription(sub);
2825
+ }
2826
+ this.config.logger.warning(
2827
+ `PolymarketRTDS: Unsupported subscription type '${sub.type}'`
2828
+ );
2829
+ return null;
2830
+ }
2831
+ mapClobMarketSubscription(sub) {
2832
+ return {
2833
+ topic: "clob_market",
2834
+ type: sub.messageType || "*",
2835
+ filters: JSON.stringify([sub.marketId])
2836
+ };
2837
+ }
2838
+ mapClobUserSubscription(sub) {
2839
+ if (!this.config.clobAuth) {
2840
+ this.config.logger.warning(
2841
+ "PolymarketRTDS: clob_user subscription requires clobAuth credentials"
2842
+ );
2843
+ }
2844
+ return {
2845
+ topic: "clob_user",
2846
+ type: sub.messageType || "*",
2847
+ clob_auth: this.config.clobAuth
2848
+ };
2849
+ }
2850
+ mapActivitySubscription(sub) {
2851
+ let filters;
2852
+ if (sub.eventSlug) {
2853
+ filters = JSON.stringify({ event_slug: sub.eventSlug });
2854
+ } else if (sub.marketSlug) {
2855
+ filters = JSON.stringify({ market_slug: sub.marketSlug });
2856
+ }
2857
+ return {
2858
+ topic: "activity",
2859
+ type: sub.messageType || "*",
2860
+ filters
2861
+ };
2862
+ }
2863
+ mapCommentsSubscription(sub) {
2864
+ let filters;
2865
+ if (sub.parentEntityId && sub.parentEntityType) {
2866
+ filters = JSON.stringify({
2867
+ parentEntityID: sub.parentEntityId,
2868
+ parentEntityType: sub.parentEntityType
2869
+ });
2870
+ }
2871
+ return {
2872
+ topic: "comments",
2873
+ type: sub.messageType || "*",
2874
+ filters
2875
+ };
2876
+ }
2877
+ mapCryptoPricesSubscription(sub) {
2878
+ let filters;
2879
+ if (sub.symbol) {
2880
+ filters = JSON.stringify({ symbol: sub.symbol.toLowerCase() });
2881
+ }
2882
+ return {
2883
+ topic: "crypto_prices",
2884
+ type: "update",
2885
+ filters
2886
+ };
2887
+ }
2888
+ mapRfqSubscription(sub) {
2889
+ return {
2890
+ topic: "rfq",
2891
+ type: sub.messageType || "*"
2892
+ };
2893
+ }
2894
+ mapMarketSubscription(sub) {
2895
+ switch (sub.type) {
2896
+ case "price":
2897
+ return {
2898
+ topic: "clob_market",
2899
+ type: "price_change",
2900
+ filters: JSON.stringify([sub.market])
2901
+ };
2902
+ case "orderbook":
2903
+ return {
2904
+ topic: "clob_market",
2905
+ type: "agg_orderbook",
2906
+ filters: JSON.stringify([sub.market])
2907
+ };
2908
+ case "trade":
2909
+ return {
2910
+ topic: "activity",
2911
+ type: "trades",
2912
+ filters: JSON.stringify({ market_slug: sub.market })
2913
+ };
2914
+ case "fill":
2915
+ if (!this.config.clobAuth) {
2916
+ this.config.logger.warning(
2917
+ "PolymarketRTDS: fill subscription requires clobAuth credentials"
2918
+ );
2919
+ }
2920
+ return {
2921
+ topic: "clob_user",
2922
+ type: "order",
2923
+ clob_auth: this.config.clobAuth
2924
+ };
2925
+ default:
2926
+ return {
2927
+ topic: "activity",
2928
+ type: "trades",
2929
+ filters: JSON.stringify({ market_slug: sub.market })
2930
+ };
2931
+ }
2932
+ }
2933
+ /**
2934
+ * Handle incoming RTDS messages
2935
+ */
2936
+ handleMessage(message) {
2937
+ try {
2938
+ const event = this.convertToStrategyEvent(message);
2939
+ this.config.onEvent(event);
2940
+ } catch (error) {
2941
+ this.config.logger.error(
2942
+ `PolymarketRTDS: Error processing message - ${error.message}`
2943
+ );
2944
+ }
2945
+ }
2946
+ /**
2947
+ * Convert RTDS Message to StrategyEvent
2948
+ */
2949
+ convertToStrategyEvent(message) {
2950
+ const eventType = this.mapTopicToEventType(message.topic, message.type);
2951
+ const eventData = this.extractEventData(message);
2952
+ return {
2953
+ type: eventType,
2954
+ timestamp: message.timestamp || Date.now(),
2955
+ market: eventData.market,
2956
+ data: eventData
2957
+ };
2958
+ }
2959
+ /**
2960
+ * Map RTDS topic/type to SDK EventType
2961
+ */
2962
+ mapTopicToEventType(topic, type) {
2963
+ switch (topic) {
2964
+ case "crypto_prices":
2965
+ return "price";
2966
+ case "clob_market":
2967
+ switch (type) {
2968
+ case "price_change":
2969
+ case "last_trade_price":
2970
+ return "price";
2971
+ case "agg_orderbook":
2972
+ return "orderbook";
2973
+ default:
2974
+ return "custom";
2975
+ }
2976
+ case "activity":
2977
+ return "trade";
2978
+ case "clob_user":
2979
+ return type === "trade" ? "trade" : "fill";
2980
+ default:
2981
+ return "custom";
2982
+ }
2983
+ }
2984
+ /**
2985
+ * Extract event data from RTDS message payload
2986
+ */
2987
+ extractEventData(message) {
2988
+ const payload = message.payload;
2989
+ const data = {
2990
+ raw: {
2991
+ topic: message.topic,
2992
+ type: message.type,
2993
+ ...payload
2994
+ }
2995
+ };
2996
+ switch (message.topic) {
2997
+ case "crypto_prices":
2998
+ data.price = payload.value;
2999
+ data.market = payload.symbol;
3000
+ break;
3001
+ case "clob_market":
3002
+ if (message.type === "price_change") {
3003
+ data.market = payload.market;
3004
+ if (payload.price_changes?.length > 0) {
3005
+ const change = payload.price_changes[0];
3006
+ data.bestBid = parseFloat(change.best_bid);
3007
+ data.bestAsk = parseFloat(change.best_ask);
3008
+ data.price = parseFloat(change.price);
3009
+ }
3010
+ } else if (message.type === "agg_orderbook") {
3011
+ data.market = payload.market;
3012
+ data.bids = payload.bids;
3013
+ data.asks = payload.asks;
3014
+ if (payload.bids?.length > 0) {
3015
+ data.bestBid = parseFloat(payload.bids[0].price);
3016
+ }
3017
+ if (payload.asks?.length > 0) {
3018
+ data.bestAsk = parseFloat(payload.asks[0].price);
3019
+ }
3020
+ } else if (message.type === "last_trade_price") {
3021
+ data.market = payload.market;
3022
+ data.price = parseFloat(payload.price);
3023
+ data.side = payload.side;
3024
+ data.size = parseFloat(payload.size);
3025
+ }
3026
+ break;
3027
+ case "activity":
3028
+ data.market = payload.slug || payload.conditionId;
3029
+ data.price = payload.price;
3030
+ data.size = payload.size;
3031
+ data.side = payload.side?.toLowerCase();
3032
+ data.tradeId = payload.transactionHash;
3033
+ break;
3034
+ case "clob_user":
3035
+ data.market = payload.market;
3036
+ data.orderId = payload.id;
3037
+ data.price = parseFloat(payload.price);
3038
+ data.size = parseFloat(payload.size || payload.original_size);
3039
+ data.side = payload.side?.toLowerCase();
3040
+ break;
3041
+ case "rfq":
3042
+ data.market = payload.market;
3043
+ data.price = payload.price;
3044
+ data.size = payload.sizeIn || payload.sizeOut;
3045
+ data.side = payload.side?.toLowerCase();
3046
+ break;
3047
+ }
3048
+ return data;
3049
+ }
3050
+ };
3051
+ function createPolymarketRTDSService(config) {
3052
+ return new PolymarketRTDSService(config);
3053
+ }
3054
+ var DEFAULT_OSIRIS_RTDS_URL = "wss://rtds.osirislabs.xyz";
3055
+ var OsirisRTDSService = class {
3056
+ ws = null;
3057
+ config;
3058
+ isConnected = false;
3059
+ reconnectAttempts = 0;
3060
+ reconnectTimeout = null;
3061
+ pingInterval = null;
3062
+ isIntentionallyClosed = false;
3063
+ activeTopics = /* @__PURE__ */ new Set();
3064
+ // Reconnection settings
3065
+ maxReconnectAttempts;
3066
+ baseReconnectDelay;
3067
+ maxReconnectDelay;
3068
+ pingIntervalMs;
3069
+ url;
3070
+ constructor(config) {
3071
+ this.config = config;
3072
+ this.maxReconnectAttempts = config.reconnect?.maxAttempts ?? 10;
3073
+ this.baseReconnectDelay = config.reconnect?.delayMs ?? 1e3;
3074
+ this.maxReconnectDelay = config.reconnect?.maxDelayMs ?? 3e4;
3075
+ this.pingIntervalMs = config.pingIntervalMs ?? 3e4;
3076
+ this.url = config.url || DEFAULT_OSIRIS_RTDS_URL;
3077
+ }
3078
+ /**
3079
+ * Connect to the Osiris Pub/Sub WebSocket
3080
+ */
3081
+ connect() {
3082
+ if (this.isConnected) {
3083
+ this.config.logger.warning("OsirisRTDS: Already connected");
3084
+ return;
3085
+ }
3086
+ this.isIntentionallyClosed = false;
3087
+ this.config.logger.info(`OsirisRTDS: Connecting to ${this.url}...`);
3088
+ try {
3089
+ this.ws = new WebSocket(this.url);
3090
+ this.ws.on("open", () => {
3091
+ this.isConnected = true;
3092
+ this.reconnectAttempts = 0;
3093
+ this.config.logger.info("OsirisRTDS: Connected");
3094
+ this.startPingInterval();
3095
+ this.config.onConnect?.();
3096
+ });
3097
+ this.ws.on("message", (data) => {
3098
+ this.handleMessage(data);
3099
+ });
3100
+ this.ws.on("error", (error) => {
3101
+ this.config.logger.error(`OsirisRTDS: Error - ${error.message}`);
3102
+ this.config.onError?.(error);
3103
+ });
3104
+ this.ws.on("close", (code, reason) => {
3105
+ this.isConnected = false;
3106
+ this.stopPingInterval();
3107
+ const reasonStr = reason.toString() || "none";
3108
+ this.config.logger.info(`OsirisRTDS: Disconnected (code: ${code}, reason: ${reasonStr})`);
3109
+ this.config.onDisconnect?.();
3110
+ if (!this.isIntentionallyClosed) {
3111
+ this.attemptReconnect();
3112
+ }
3113
+ });
3114
+ } catch (error) {
3115
+ this.config.logger.error(`OsirisRTDS: Connection failed - ${error.message}`);
3116
+ if (!this.isIntentionallyClosed) {
3117
+ this.attemptReconnect();
3118
+ }
3119
+ }
3120
+ }
3121
+ /**
3122
+ * Disconnect from the Osiris Pub/Sub WebSocket
3123
+ */
3124
+ disconnect() {
3125
+ this.isIntentionallyClosed = true;
3126
+ this.stopPingInterval();
3127
+ if (this.reconnectTimeout) {
3128
+ clearTimeout(this.reconnectTimeout);
3129
+ this.reconnectTimeout = null;
3130
+ }
3131
+ if (this.ws) {
3132
+ this.config.logger.info("OsirisRTDS: Disconnecting...");
3133
+ try {
3134
+ if (this.activeTopics.size > 0) {
3135
+ this.unsubscribeFromTopics(Array.from(this.activeTopics));
3136
+ }
3137
+ this.ws.close(1e3, "Intentional close");
3138
+ } catch {
3139
+ }
3140
+ this.ws = null;
3141
+ }
3142
+ this.isConnected = false;
3143
+ this.activeTopics.clear();
3144
+ }
3145
+ /**
3146
+ * Check if connected
3147
+ */
3148
+ isActive() {
3149
+ return this.isConnected;
3150
+ }
3151
+ /**
3152
+ * Subscribe to events
3153
+ */
3154
+ subscribe(subscriptions) {
3155
+ if (!this.ws || !this.isConnected) {
3156
+ this.config.logger.warning("OsirisRTDS: Cannot subscribe - not connected");
3157
+ return;
3158
+ }
3159
+ const { topics, filters } = this.mapToOsirisSubscriptions(subscriptions);
3160
+ if (topics.length === 0) {
3161
+ this.config.logger.warning("OsirisRTDS: No valid topics to subscribe");
3162
+ return;
3163
+ }
3164
+ const message = {
3165
+ action: "subscribe",
3166
+ topics,
3167
+ ...Object.keys(filters).length > 0 ? { filters } : {}
3168
+ };
3169
+ try {
3170
+ this.ws.send(JSON.stringify(message));
3171
+ topics.forEach((t) => this.activeTopics.add(t));
3172
+ this.config.logger.info(`OsirisRTDS: Subscribing to ${topics.join(", ")}`);
3173
+ } catch (error) {
3174
+ this.config.logger.error(`OsirisRTDS: Failed to subscribe - ${error.message}`);
3175
+ }
3176
+ }
3177
+ /**
3178
+ * Unsubscribe from topics
3179
+ */
3180
+ unsubscribe(subscriptions) {
3181
+ if (!this.ws || !this.isConnected) {
3182
+ return;
3183
+ }
3184
+ const { topics } = this.mapToOsirisSubscriptions(subscriptions);
3185
+ this.unsubscribeFromTopics(topics);
3186
+ }
3187
+ /**
3188
+ * Unsubscribe from topics by name
3189
+ */
3190
+ unsubscribeFromTopics(topics) {
3191
+ if (topics.length === 0) return;
3192
+ const message = {
3193
+ action: "unsubscribe",
3194
+ topics
3195
+ };
3196
+ try {
3197
+ this.ws?.send(JSON.stringify(message));
3198
+ topics.forEach((t) => this.activeTopics.delete(t));
3199
+ this.config.logger.info(`OsirisRTDS: Unsubscribed from ${topics.join(", ")}`);
3200
+ } catch {
3201
+ }
3202
+ }
3203
+ /**
3204
+ * Send ping to keep connection alive
3205
+ */
3206
+ ping() {
3207
+ if (this.ws && this.isConnected) {
3208
+ try {
3209
+ this.ws.send(JSON.stringify({ action: "ping" }));
3210
+ } catch {
3211
+ }
3212
+ }
3213
+ }
3214
+ /**
3215
+ * Map SDK subscriptions to Osiris Pub/Sub format
3216
+ */
3217
+ mapToOsirisSubscriptions(subscriptions) {
3218
+ const topics = [];
3219
+ const filters = {};
3220
+ for (const sub of subscriptions) {
3221
+ const topic = this.mapSubscriptionToTopic(sub);
3222
+ if (topic) {
3223
+ topics.push(topic);
3224
+ if (sub.conditions) {
3225
+ filters[topic] = sub.conditions;
3226
+ }
3227
+ }
3228
+ }
3229
+ return { topics, filters };
3230
+ }
3231
+ /**
3232
+ * Map SDK subscription to Osiris topic string
3233
+ */
3234
+ mapSubscriptionToTopic(sub) {
3235
+ if (isMarketSubscription(sub)) {
3236
+ return sub.market ? `market:${sub.market}` : null;
3237
+ }
3238
+ if (isWalletSubscription(sub)) {
3239
+ return sub.wallet ? `wallet:${sub.wallet.toLowerCase()}` : null;
3240
+ }
3241
+ if (isOpportunitySubscription(sub)) {
3242
+ return `opps:${sub.filter || "all"}`;
3243
+ }
3244
+ if (isCustomSubscription(sub)) {
3245
+ return sub.topic || null;
3246
+ }
3247
+ return null;
3248
+ }
3249
+ /**
3250
+ * Start ping interval
3251
+ */
3252
+ startPingInterval() {
3253
+ this.stopPingInterval();
3254
+ this.pingInterval = setInterval(() => this.ping(), this.pingIntervalMs);
3255
+ }
3256
+ /**
3257
+ * Stop ping interval
3258
+ */
3259
+ stopPingInterval() {
3260
+ if (this.pingInterval) {
3261
+ clearInterval(this.pingInterval);
3262
+ this.pingInterval = null;
3263
+ }
3264
+ }
3265
+ /**
3266
+ * Attempt reconnection with exponential backoff
3267
+ */
3268
+ attemptReconnect() {
3269
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
3270
+ this.config.logger.error(
3271
+ `OsirisRTDS: Max reconnection attempts (${this.maxReconnectAttempts}) reached`
3272
+ );
3273
+ return;
3274
+ }
3275
+ this.reconnectAttempts++;
3276
+ const delay = Math.min(
3277
+ this.baseReconnectDelay * Math.pow(2, this.reconnectAttempts - 1) + Math.random() * 1e3,
3278
+ this.maxReconnectDelay
3279
+ );
3280
+ this.config.logger.info(
3281
+ `OsirisRTDS: Reconnecting in ${Math.round(delay)}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`
3282
+ );
3283
+ this.reconnectTimeout = setTimeout(() => {
3284
+ this.reconnectTimeout = null;
3285
+ this.connect();
3286
+ }, delay);
3287
+ }
3288
+ /**
3289
+ * Handle incoming WebSocket messages
3290
+ */
3291
+ handleMessage(data) {
3292
+ try {
3293
+ const rawData = typeof data === "string" ? data : data.toString();
3294
+ if (!rawData.trim()) return;
3295
+ let message;
3296
+ try {
3297
+ message = JSON.parse(rawData);
3298
+ } catch {
3299
+ this.config.logger.warning(`OsirisRTDS: Non-JSON message received`);
3300
+ return;
3301
+ }
3302
+ switch (message.type) {
3303
+ case "connected":
3304
+ this.config.logger.info(`OsirisRTDS: ${message.message}`);
3305
+ return;
3306
+ case "subscribe.result":
3307
+ if (message.success) {
3308
+ this.config.logger.info(
3309
+ `OsirisRTDS: Subscribed to ${message.subscribed?.join(", ")}`
3310
+ );
3311
+ } else {
3312
+ this.config.logger.error(
3313
+ `OsirisRTDS: Subscription failed - ${message.errors?.join(", ")}`
3314
+ );
3315
+ }
3316
+ return;
3317
+ case "error":
3318
+ this.config.logger.error(`OsirisRTDS: Server error - ${message.error}`);
3319
+ return;
3320
+ case "pong":
3321
+ return;
3322
+ }
3323
+ const event = this.convertToStrategyEvent(message);
3324
+ if (event) {
3325
+ this.config.onEvent(event);
3326
+ }
3327
+ } catch (error) {
3328
+ this.config.logger.error(`OsirisRTDS: Error processing message - ${error.message}`);
3329
+ }
3330
+ }
3331
+ /**
3332
+ * Convert Osiris message to StrategyEvent
3333
+ */
3334
+ convertToStrategyEvent(message) {
3335
+ const timestamp = message.ts || Date.now();
3336
+ switch (message.type) {
3337
+ case "market.analysis":
3338
+ return {
3339
+ type: "price",
3340
+ // Market analysis treated as price/market update
3341
+ market: message.slug,
3342
+ timestamp,
3343
+ data: {
3344
+ ...message.data,
3345
+ raw: message
3346
+ }
3347
+ };
3348
+ case "wallet.analysis":
3349
+ return {
3350
+ type: "wallet",
3351
+ wallet: message.address,
3352
+ timestamp,
3353
+ data: {
3354
+ ...message.data,
3355
+ raw: message
3356
+ }
3357
+ };
3358
+ case "opportunity":
3359
+ return {
3360
+ type: "opportunity",
3361
+ market: message.slug,
3362
+ timestamp,
3363
+ data: {
3364
+ ...message.data,
3365
+ raw: message
3366
+ }
3367
+ };
3368
+ default:
3369
+ return null;
3370
+ }
3371
+ }
3372
+ };
3373
+ function createOsirisRTDSService(config) {
3374
+ return new OsirisRTDSService(config);
3375
+ }
3376
+
3377
+ // src/rtds/unified-rtds.service.ts
3378
+ var UnifiedRTDSService = class {
3379
+ config;
3380
+ polymarketService = null;
3381
+ osirisService = null;
3382
+ polymarketConnected = false;
3383
+ osirisConnected = false;
3384
+ constructor(config) {
3385
+ this.config = config;
3386
+ this.initializeServices();
3387
+ }
3388
+ /**
3389
+ * Initialize the underlying services based on configuration
3390
+ */
3391
+ initializeServices() {
3392
+ if (this.config.polymarket?.enabled !== false) {
3393
+ this.polymarketService = new PolymarketRTDSService({
3394
+ logger: this.config.logger,
3395
+ onEvent: this.config.onEvent,
3396
+ onError: this.config.onError,
3397
+ onConnect: () => {
3398
+ this.polymarketConnected = true;
3399
+ this.checkAllConnected();
3400
+ },
3401
+ onDisconnect: () => {
3402
+ this.polymarketConnected = false;
3403
+ this.checkAnyDisconnected();
3404
+ },
3405
+ clobAuth: this.config.polymarket?.clobAuth
3406
+ });
3407
+ }
3408
+ if (this.config.osiris?.enabled !== false) {
3409
+ this.osirisService = new OsirisRTDSService({
3410
+ logger: this.config.logger,
3411
+ onEvent: this.config.onEvent,
3412
+ onError: this.config.onError,
3413
+ onConnect: () => {
3414
+ this.osirisConnected = true;
3415
+ this.checkAllConnected();
3416
+ },
3417
+ onDisconnect: () => {
3418
+ this.osirisConnected = false;
3419
+ this.checkAnyDisconnected();
3420
+ },
3421
+ url: this.config.osiris?.url || DEFAULT_OSIRIS_RTDS_URL,
3422
+ pingIntervalMs: this.config.osiris?.pingIntervalMs,
3423
+ reconnect: this.config.reconnect
3424
+ });
3425
+ }
3426
+ }
3427
+ /**
3428
+ * Connect to all enabled services
3429
+ */
3430
+ connect() {
3431
+ this.config.logger.info("UnifiedRTDS: Connecting to enabled services...");
3432
+ if (this.polymarketService) {
3433
+ this.polymarketService.connect();
3434
+ }
3435
+ if (this.osirisService) {
3436
+ this.osirisService.connect();
3437
+ }
3438
+ }
3439
+ /**
3440
+ * Disconnect from all services
3441
+ */
3442
+ disconnect() {
3443
+ this.config.logger.info("UnifiedRTDS: Disconnecting from all services...");
3444
+ if (this.polymarketService) {
3445
+ this.polymarketService.disconnect();
3446
+ }
3447
+ if (this.osirisService) {
3448
+ this.osirisService.disconnect();
3449
+ }
3450
+ }
3451
+ /**
3452
+ * Check if connected to at least one service
3453
+ */
3454
+ isActive() {
3455
+ return (this.polymarketService?.isActive() ?? false) || (this.osirisService?.isActive() ?? false);
3456
+ }
3457
+ /**
3458
+ * Get connection status for each service
3459
+ */
3460
+ getStatus() {
3461
+ return {
3462
+ polymarket: {
3463
+ enabled: this.polymarketService !== null,
3464
+ connected: this.polymarketConnected
3465
+ },
3466
+ osiris: {
3467
+ enabled: this.osirisService !== null,
3468
+ connected: this.osirisConnected
3469
+ }
3470
+ };
3471
+ }
3472
+ /**
3473
+ * Subscribe to events
3474
+ * Automatically routes subscriptions to the appropriate backend
3475
+ */
3476
+ subscribe(subscriptions) {
3477
+ const { polymarketSubs, osirisSubs } = this.routeSubscriptions(subscriptions);
3478
+ if (polymarketSubs.length > 0) {
3479
+ if (this.polymarketService) {
3480
+ this.polymarketService.subscribe(polymarketSubs);
3481
+ } else {
3482
+ this.config.logger.warning(
3483
+ "UnifiedRTDS: Polymarket subscriptions requested but service not enabled"
3484
+ );
3485
+ }
3486
+ }
3487
+ if (osirisSubs.length > 0) {
3488
+ if (this.osirisService) {
3489
+ this.osirisService.subscribe(osirisSubs);
3490
+ } else {
3491
+ this.config.logger.warning(
3492
+ "UnifiedRTDS: Osiris subscriptions requested but service not enabled"
3493
+ );
3494
+ }
3495
+ }
3496
+ }
3497
+ /**
3498
+ * Unsubscribe from events
3499
+ */
3500
+ unsubscribe(subscriptions) {
3501
+ const { polymarketSubs, osirisSubs } = this.routeSubscriptions(subscriptions);
3502
+ if (polymarketSubs.length > 0 && this.polymarketService) {
3503
+ this.polymarketService.unsubscribe(polymarketSubs);
3504
+ }
3505
+ if (osirisSubs.length > 0 && this.osirisService) {
3506
+ this.osirisService.unsubscribe(osirisSubs);
3507
+ }
3508
+ }
3509
+ /**
3510
+ * Route subscriptions to appropriate backends based on type and eventSource
3511
+ */
3512
+ routeSubscriptions(subscriptions) {
3513
+ const polymarketSubs = [];
3514
+ const osirisSubs = [];
3515
+ for (const sub of subscriptions) {
3516
+ if (sub.eventSource === "polymarket") {
3517
+ polymarketSubs.push(sub);
3518
+ continue;
3519
+ }
3520
+ if (sub.eventSource === "osiris") {
3521
+ osirisSubs.push(sub);
3522
+ continue;
3523
+ }
3524
+ if (isPolymarketSubscription(sub)) {
3525
+ polymarketSubs.push(sub);
3526
+ } else if (isOsirisSubscription(sub)) {
3527
+ osirisSubs.push(sub);
3528
+ } else if (isMarketSubscription(sub)) {
3529
+ polymarketSubs.push(sub);
3530
+ } else if (isCustomSubscription(sub)) {
3531
+ const topic = sub.topic;
3532
+ if (topic.startsWith("market:") || topic.startsWith("wallet:") || topic.startsWith("opps:")) {
3533
+ osirisSubs.push(sub);
3534
+ } else {
3535
+ polymarketSubs.push(sub);
3536
+ }
3537
+ } else {
3538
+ polymarketSubs.push(sub);
3539
+ }
3540
+ }
3541
+ return { polymarketSubs, osirisSubs };
3542
+ }
3543
+ /**
3544
+ * Check if all enabled services are connected
3545
+ */
3546
+ checkAllConnected() {
3547
+ const polymarketOk = !this.polymarketService || this.polymarketConnected;
3548
+ const osirisOk = !this.osirisService || this.osirisConnected;
3549
+ if (polymarketOk && osirisOk) {
3550
+ this.config.onConnect?.();
3551
+ }
3552
+ }
3553
+ /**
3554
+ * Check if any service disconnected
3555
+ */
3556
+ checkAnyDisconnected() {
3557
+ if (!this.polymarketConnected && !this.osirisConnected) {
3558
+ this.config.onDisconnect?.();
3559
+ }
3560
+ }
3561
+ };
3562
+ function createUnifiedRTDSService(config) {
3563
+ return new UnifiedRTDSService(config);
3564
+ }
2528
3565
  var CHAIN_MAP = {
2529
3566
  "evm:eip155:1": mainnet,
2530
3567
  "evm:eip155:137": polygon,
@@ -2675,6 +3712,6 @@ var Signer = class {
2675
3712
  }
2676
3713
  };
2677
3714
 
2678
- export { HyperliquidClient, MemoryStateManager, OsirisEventRunner, OsirisSigner, PolymarketClient, PolymarketEventRunner, PrivateKeySigner, RedisStateManager, Signer, StrategyEngine, createConsoleLogger, createEventRunner, createOsirisContext, createPolymarketEventRunner, createStrategyEngine, isCustomSubscription, isEventBasedStrategy, isMarketSubscription, isOpportunitySubscription, isTickBasedStrategy, isWalletSubscription, runStrategy, validateStrategy };
3715
+ export { DEFAULT_OSIRIS_RTDS_URL, HyperliquidClient, MemoryStateManager, OsirisEventRunner, OsirisRTDSService, OsirisSigner, PolymarketClient, PolymarketEventRunner, PolymarketRTDSService, PrivateKeySigner, RedisStateManager, Signer, StrategyEngine, UnifiedRTDSService, createConsoleLogger, createEventRunner, createOsirisContext, createOsirisRTDSService, createPolymarketEventRunner, createPolymarketRTDSService, createStrategyEngine, createUnifiedRTDSService, isActivitySubscription, isClobMarketSubscription, isClobUserSubscription, isCommentsSubscription, isCryptoPricesSubscription, isCustomSubscription, isEventBasedStrategy, isMarketSubscription, isOpportunitySubscription, isOsirisSubscription, isPolymarketSubscription, isRfqSubscription, isTickBasedStrategy, isWalletSubscription, runStrategy, validateStrategy };
2679
3716
  //# sourceMappingURL=index.js.map
2680
3717
  //# sourceMappingURL=index.js.map