@codex-data/sdk 2.4.12 → 2.5.2

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/README.md CHANGED
@@ -305,6 +305,33 @@ const unsubscribe = sdk.subscriptions.onEventsCreated(
305
305
  );
306
306
  ```
307
307
 
308
+ ## Edge Subscriptions
309
+
310
+ Pass `{ useEdge: true }` as the third argument to a generated subscription method (or the fourth argument to `sdk.subscribe`) to use a regional edge node. Solana (`1399811149`) routes to `wss://fra.edge.codex.io/graphql`; Robinhood Chain (`4663`) routes to `wss://iad.edge.codex.io/graphql`. Connections are created on demand and reused per endpoint.
311
+
312
+ ```typescript
313
+ import { Codex, EventCommitmentLevel } from "@codex-data/sdk";
314
+
315
+ const sdk = new Codex(process.env.CODEX_API_KEY!);
316
+
317
+ const unsubscribe = sdk.subscriptions.onTokenEventsCreated(
318
+ {
319
+ input: { tokenAddress: "0x...", networkId: 4663 },
320
+ commitmentLevel: [EventCommitmentLevel.Processed],
321
+ },
322
+ {
323
+ next: (result) => console.log(result.data),
324
+ error: (err) => console.error(err),
325
+ complete: () => console.log("Stream ended"),
326
+ },
327
+ { useEdge: true },
328
+ );
329
+ ```
330
+
331
+ Edge supports `onEventsCreated`, `onTokenEventsCreated`, `onBarsUpdated`, and `onTokenBarsUpdated`. The commitment levels must include `Processed`, and `onBarsUpdated` requires an explicit `quoteToken`. Each subscription must target one supported chain. Subscriptions without `useEdge` use the main endpoint.
332
+
333
+ The lightweight `withEdge` helper from `@codex-data/sdk/edge` uses the same routing. For a standalone Robinhood connection, pass `url: ROBINHOOD_EDGE_URL` to `createEdgeClient`, importing both from `@codex-data/sdk/edge`. The SDK's `apiEdgeUrl` and the helper's `edgeUrl` override routing for all chains.
334
+
308
335
  ## Custom Queries: Request Only the Fields You Need
309
336
 
310
337
  The built-in `sdk.queries.*` methods select every available field, so the recipes above are the most expensive way to call each endpoint. Writing your own query means you get smaller, faster responses.
package/dist/edge.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { createClient, createEdgeClient, DEFAULT_EDGE_URL, withEdge, } from "./sdk/edge";
1
+ export { createClient, createEdgeClient, DEFAULT_EDGE_URL, ROBINHOOD_EDGE_URL, withEdge, } from "./sdk/edge";
2
2
  export type { ClientWithEdge, EdgeClientOptions, SubscriptionOptions, } from "./sdk/edge";
package/dist/edge.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withEdge = exports.DEFAULT_EDGE_URL = exports.createEdgeClient = exports.createClient = void 0;
3
+ exports.withEdge = exports.ROBINHOOD_EDGE_URL = exports.DEFAULT_EDGE_URL = exports.createEdgeClient = exports.createClient = void 0;
4
4
  var edge_1 = require("./sdk/edge");
5
5
  Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return edge_1.createClient; } });
6
6
  Object.defineProperty(exports, "createEdgeClient", { enumerable: true, get: function () { return edge_1.createEdgeClient; } });
7
7
  Object.defineProperty(exports, "DEFAULT_EDGE_URL", { enumerable: true, get: function () { return edge_1.DEFAULT_EDGE_URL; } });
8
+ Object.defineProperty(exports, "ROBINHOOD_EDGE_URL", { enumerable: true, get: function () { return edge_1.ROBINHOOD_EDGE_URL; } });
8
9
  Object.defineProperty(exports, "withEdge", { enumerable: true, get: function () { return edge_1.withEdge; } });
package/dist/edge.mjs CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  // src/sdk/edgeSubscription.ts
7
7
  import { getOperationAST, Kind, parse, valueFromASTUntyped } from "graphql";
8
8
  var SOLANA_NETWORK_ID = 1399811149;
9
+ var ROBINHOOD_NETWORK_ID = 4663;
9
10
  var SUPPORTED_OPERATIONS = /* @__PURE__ */ new Set([
10
11
  "onEventsCreated",
11
12
  "onTokenEventsCreated",
@@ -15,7 +16,7 @@ var SUPPORTED_OPERATIONS = /* @__PURE__ */ new Set([
15
16
  function assertEdgeSubscription(payload) {
16
17
  function fail() {
17
18
  throw new Error(
18
- "useEdge requires a supported Solana subscription with commitmentLevel including Processed"
19
+ "useEdge requires a supported Solana or Robinhood subscription with commitmentLevel including Processed"
19
20
  );
20
21
  }
21
22
  const document = parse(payload.query);
@@ -58,15 +59,21 @@ function assertEdgeSubscription(payload) {
58
59
  }
59
60
  };
60
61
  collect(args);
61
- if (!networks.length || networks.some((network) => network !== SOLANA_NETWORK_ID))
62
+ const networkId = networks[0];
63
+ if (networkId !== SOLANA_NETWORK_ID && networkId !== ROBINHOOD_NETWORK_ID || networks.some((network) => network !== networkId))
62
64
  fail();
63
65
  if (field.name.value === "onBarsUpdated" && args.quoteToken == null) {
64
66
  throw new Error("useEdge onBarsUpdated requires an explicit quoteToken");
65
67
  }
68
+ return networkId;
66
69
  }
67
70
 
68
71
  // src/sdk/edge.ts
69
72
  var DEFAULT_EDGE_URL = "wss://fra.edge.codex.io/graphql";
73
+ var ROBINHOOD_EDGE_URL = "wss://iad.edge.codex.io/graphql";
74
+ function edgeUrlForNetwork(networkId) {
75
+ return networkId === ROBINHOOD_NETWORK_ID ? ROBINHOOD_EDGE_URL : DEFAULT_EDGE_URL;
76
+ }
70
77
  function createEdgeClient(options) {
71
78
  return createClient({ ...options, url: options.url ?? DEFAULT_EDGE_URL });
72
79
  }
@@ -74,11 +81,10 @@ function prepareEdgeSubscription(payload, replacer) {
74
81
  const snapshot = JSON.parse(
75
82
  JSON.stringify(payload, replacer)
76
83
  );
77
- assertEdgeSubscription(snapshot);
78
- return snapshot;
84
+ return { payload: snapshot, networkId: assertEdgeSubscription(snapshot) };
79
85
  }
80
86
  function withEdge(main, options) {
81
- const { edgeUrl = DEFAULT_EDGE_URL, ...wsOptions } = options;
87
+ const { edgeUrl, ...wsOptions } = options;
82
88
  const mainHandlers = /* @__PURE__ */ new Set();
83
89
  const edgeHandlers = new Set(
84
90
  wsOptions.on ? [wsOptions.on] : []
@@ -105,7 +111,7 @@ function withEdge(main, options) {
105
111
  main.on("message", mainEvents.message);
106
112
  main.on("closed", mainEvents.closed);
107
113
  main.on("error", mainEvents.error);
108
- let edge;
114
+ const edges = /* @__PURE__ */ new Map();
109
115
  let disposed = false;
110
116
  return {
111
117
  ...main,
@@ -121,36 +127,43 @@ function withEdge(main, options) {
121
127
  subscribe: (payload, sink, subscriptionOptions = {}) => {
122
128
  if (disposed) throw new Error("Edge client has been disposed");
123
129
  if (!subscriptionOptions.useEdge) return main.subscribe(payload, sink);
124
- const snapshot = prepareEdgeSubscription(
130
+ const { payload: snapshot, networkId } = prepareEdgeSubscription(
125
131
  payload,
126
132
  wsOptions.jsonMessageReplacer
127
133
  );
134
+ const url = edgeUrl ?? edgeUrlForNetwork(networkId);
135
+ let edge = edges.get(url);
128
136
  if (!edge) {
129
137
  let subscriptionMessage = false;
130
138
  edge = createEdgeClient({
131
139
  ...wsOptions,
132
- url: edgeUrl,
140
+ url,
133
141
  on: handlersFor(true),
134
142
  jsonMessageReplacer: function(key, value) {
135
143
  if (key === "") subscriptionMessage = value?.type === "subscribe";
136
144
  return subscriptionMessage ? value : wsOptions.jsonMessageReplacer ? wsOptions.jsonMessageReplacer.call(this, key, value) : value;
137
145
  }
138
146
  });
147
+ edges.set(url, edge);
139
148
  }
140
149
  return edge.subscribe(snapshot, sink);
141
150
  },
142
151
  terminate: () => {
143
152
  main.terminate();
144
- edge?.terminate();
153
+ edges.forEach((edge) => edge.terminate());
145
154
  },
146
155
  dispose: async () => {
147
156
  disposed = true;
148
- await Promise.all([main.dispose(), edge?.dispose()]);
157
+ await Promise.all([
158
+ main.dispose(),
159
+ ...Array.from(edges.values(), (edge) => edge.dispose())
160
+ ]);
149
161
  }
150
162
  };
151
163
  }
152
164
  export {
153
165
  DEFAULT_EDGE_URL,
166
+ ROBINHOOD_EDGE_URL,
154
167
  createClient,
155
168
  createEdgeClient,
156
169
  withEdge
@@ -1,4 +1,4 @@
1
- import { ApiTokenQueryVariables, ApiTokensQueryVariables, BalancesQueryVariables, BlocksQueryVariables, CategoriesQueryVariables, CategoryQueryVariables, CategoryTokensQueryVariables, ChartUrlsQueryVariables, DetailedPredictionEventStatsQueryVariables, DetailedPredictionMarketStatsQueryVariables, DetailedPredictionTraderStatsQueryVariables, DetailedWalletStatsQueryVariables, EventScopedFilterPredictionMarketsQueryVariables, FilterExchangesQueryVariables, FilterLaunchpadsQueryVariables, FilterNetworksQueryVariables, FilterPairsQueryVariables, FilterPredictionEventsQueryVariables, FilterPredictionMarketsQueryVariables, FilterPredictionTraderMarketsQueryVariables, FilterPredictionTradersQueryVariables, FilterTokensQueryVariables, FilterTokenWalletsQueryVariables, FilterWalletsQueryVariables, GetBarsQueryVariables, GetCommunityNotesQueryVariables, GetDetailedPairsStatsQueryVariables, GetDetailedPairStatsQueryVariables, GetDetailedTokenStatsQueryVariables, GetEventLabelsQueryVariables, GetExchangesQueryVariables, GetNetworkConfigsQueryVariables, GetNetworksQueryVariables, GetNetworkStatsQueryVariables, GetNetworkStatusQueryVariables, GetSimulateTokenContractResultsQueryVariables, GetSymbolQueryVariables, GetTokenBarsQueryVariables, GetTokenEventsForMakerQueryVariables, GetTokenEventsQueryVariables, GetTokenPricesQueryVariables, GetWebhooksQueryVariables, HoldersQueryVariables, LiquidityLocksV2QueryVariables, LiquidityMetadataByTokenQueryVariables, LiquidityMetadataQueryVariables, ListPairsForTokenQueryVariables, ListPairsWithMetadataForTokenQueryVariables, PairMetadataQueryVariables, PairsQueryVariables, PredictionCategoriesQueryVariables, PredictionEventBarsQueryVariables, PredictionEventTopMarketsBarsQueryVariables, PredictionMarketBarsQueryVariables, PredictionMarketPriceQueryVariables, PredictionMarketsQueryVariables, PredictionOutcomeOrderBooksQueryVariables, PredictionTokenHoldersQueryVariables, PredictionTraderBarsQueryVariables, PredictionTraderHoldingsQueryVariables, PredictionTraderMarketsStatsQueryVariables, PredictionTradersQueryVariables, PredictionTradesQueryVariables, TokenQueryVariables, TokenSparklinesQueryVariables, TokensQueryVariables, TokenTopTradersQueryVariables, TokenWalletStatsQueryVariables, Top10HoldersPercentQueryVariables, WalletAggregateBackfillStateQueryVariables, WalletChartQueryVariables, WalletLabelTypesQueryVariables } from "./generated/graphql";
1
+ import { ApiTokenQueryVariables, ApiTokensQueryVariables, BalancesQueryVariables, BlocksQueryVariables, CategoriesQueryVariables, CategoryQueryVariables, CategoryTokensQueryVariables, ChartUrlsQueryVariables, DetailedPredictionEventStatsQueryVariables, DetailedPredictionMarketStatsQueryVariables, DetailedPredictionTraderStatsQueryVariables, DetailedWalletStatsQueryVariables, EventScopedFilterPredictionMarketsQueryVariables, FilterExchangesQueryVariables, FilterLaunchpadsQueryVariables, FilterNetworksQueryVariables, FilterPairsQueryVariables, FilterPredictionEventsQueryVariables, FilterPredictionMarketsQueryVariables, FilterPredictionTraderMarketsQueryVariables, FilterPredictionTradersQueryVariables, FilterTokensQueryVariables, FilterTokenWalletsQueryVariables, FilterWalletsQueryVariables, GetBarsQueryVariables, GetCommunityNotesQueryVariables, GetDetailedPairsStatsQueryVariables, GetDetailedPairStatsQueryVariables, GetDetailedTokenStatsQueryVariables, GetEventLabelsQueryVariables, GetExchangesQueryVariables, GetNetworkConfigsQueryVariables, GetNetworksQueryVariables, GetNetworkStatsQueryVariables, GetNetworkStatusQueryVariables, GetSimulateTokenContractResultsQueryVariables, GetSymbolQueryVariables, GetTokenBarsQueryVariables, GetTokenEventsForMakerQueryVariables, GetTokenEventsQueryVariables, GetTokenPricesQueryVariables, GetWebhooksQueryVariables, HoldersQueryVariables, LiquidityLocksV2QueryVariables, LiquidityMetadataByTokenQueryVariables, LiquidityMetadataQueryVariables, ListPairsForTokenQueryVariables, ListPairsWithMetadataForTokenQueryVariables, PairMetadataQueryVariables, PairsQueryVariables, PredictionCategoriesQueryVariables, PredictionEventBarsQueryVariables, PredictionEventTopMarketsBarsQueryVariables, PredictionMarketBarsQueryVariables, PredictionMarketPriceQueryVariables, PredictionMarketsQueryVariables, PredictionOutcomeOrderBooksQueryVariables, PredictionTokenHoldersQueryVariables, PredictionTraderBarsQueryVariables, PredictionTraderHoldingsQueryVariables, PredictionTraderMarketsStatsQueryVariables, PredictionTradersQueryVariables, PredictionTradesQueryVariables, TokenQueryVariables, TokenSparklinesQueryVariables, TokensQueryVariables, TokenTopTradersQueryVariables, TokenWalletStatsQueryVariables, Top10HoldersPercentQueryVariables, UsageDataQueryVariables, WalletAggregateBackfillStateQueryVariables, WalletChartQueryVariables, WalletLabelTypesQueryVariables } from "./generated/graphql";
2
2
  import { Codex } from "./index";
3
3
  export declare class Query {
4
4
  private sdk;
@@ -72,6 +72,7 @@ export declare class Query {
72
72
  tokenWalletStats: (vars: TokenWalletStatsQueryVariables) => Promise<import("./generated/graphql").TokenWalletStatsQuery>;
73
73
  tokens: (vars: TokensQueryVariables) => Promise<import("./generated/graphql").TokensQuery>;
74
74
  top10HoldersPercent: (vars: Top10HoldersPercentQueryVariables) => Promise<import("./generated/graphql").Top10HoldersPercentQuery>;
75
+ usageData: (vars: UsageDataQueryVariables) => Promise<import("./generated/graphql").UsageDataQuery>;
75
76
  walletAggregateBackfillState: (vars: WalletAggregateBackfillStateQueryVariables) => Promise<import("./generated/graphql").WalletAggregateBackfillStateQuery>;
76
77
  walletChart: (vars: WalletChartQueryVariables) => Promise<import("./generated/graphql").WalletChartQuery>;
77
78
  walletLabelTypes: (vars: WalletLabelTypesQueryVariables) => Promise<import("./generated/graphql").WalletLabelTypesQuery>;
package/dist/sdk/Query.js CHANGED
@@ -84,6 +84,7 @@ class Query {
84
84
  this.tokenWalletStats = (vars) => __awaiter(this, void 0, void 0, function* () { return this.sdk.query(graphql_1.TokenWalletStatsDocument, vars); });
85
85
  this.tokens = (vars) => __awaiter(this, void 0, void 0, function* () { return this.sdk.query(graphql_1.TokensDocument, vars); });
86
86
  this.top10HoldersPercent = (vars) => __awaiter(this, void 0, void 0, function* () { return this.sdk.query(graphql_1.Top10HoldersPercentDocument, vars); });
87
+ this.usageData = (vars) => __awaiter(this, void 0, void 0, function* () { return this.sdk.query(graphql_1.UsageDataDocument, vars); });
87
88
  this.walletAggregateBackfillState = (vars) => __awaiter(this, void 0, void 0, function* () { return this.sdk.query(graphql_1.WalletAggregateBackfillStateDocument, vars); });
88
89
  this.walletChart = (vars) => __awaiter(this, void 0, void 0, function* () { return this.sdk.query(graphql_1.WalletChartDocument, vars); });
89
90
  this.walletLabelTypes = (vars) => __awaiter(this, void 0, void 0, function* () { return this.sdk.query(graphql_1.WalletLabelTypesDocument, vars); });
@@ -1,5 +1,5 @@
1
1
  // THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT IT DIRECTLY
2
- import { ApiTokenDocument, ApiTokensDocument, BalancesDocument, BlocksDocument, CategoriesDocument, CategoryDocument, CategoryTokensDocument, ChartUrlsDocument, DetailedPredictionEventStatsDocument, DetailedPredictionMarketStatsDocument, DetailedPredictionTraderStatsDocument, DetailedWalletStatsDocument, EventScopedFilterPredictionMarketsDocument, FilterExchangesDocument, FilterLaunchpadsDocument, FilterNetworksDocument, FilterPairsDocument, FilterPredictionEventsDocument, FilterPredictionMarketsDocument, FilterPredictionTraderMarketsDocument, FilterPredictionTradersDocument, FilterTokensDocument, FilterTokenWalletsDocument, FilterWalletsDocument, GetBarsDocument, GetCommunityNotesDocument, GetDetailedPairsStatsDocument, GetDetailedPairStatsDocument, GetDetailedTokenStatsDocument, GetEventLabelsDocument, GetExchangesDocument, GetNetworkConfigsDocument, GetNetworksDocument, GetNetworkStatsDocument, GetNetworkStatusDocument, GetSimulateTokenContractResultsDocument, GetSymbolDocument, GetTokenBarsDocument, GetTokenEventsDocument, GetTokenEventsForMakerDocument, GetTokenPricesDocument, GetWebhooksDocument, HoldersDocument, LiquidityLocksV2Document, LiquidityMetadataByTokenDocument, LiquidityMetadataDocument, ListPairsForTokenDocument, ListPairsWithMetadataForTokenDocument, PairMetadataDocument, PairsDocument, PredictionCategoriesDocument, PredictionEventBarsDocument, PredictionEventTopMarketsBarsDocument, PredictionMarketBarsDocument, PredictionMarketPriceDocument, PredictionMarketsDocument, PredictionOutcomeOrderBooksDocument, PredictionTokenHoldersDocument, PredictionTraderBarsDocument, PredictionTraderHoldingsDocument, PredictionTraderMarketsStatsDocument, PredictionTradersDocument, PredictionTradesDocument, TokenDocument, TokensDocument, TokenSparklinesDocument, TokenTopTradersDocument, TokenWalletStatsDocument, Top10HoldersPercentDocument, WalletAggregateBackfillStateDocument, WalletChartDocument, WalletLabelTypesDocument, } from "./generated/graphql";
2
+ import { ApiTokenDocument, ApiTokensDocument, BalancesDocument, BlocksDocument, CategoriesDocument, CategoryDocument, CategoryTokensDocument, ChartUrlsDocument, DetailedPredictionEventStatsDocument, DetailedPredictionMarketStatsDocument, DetailedPredictionTraderStatsDocument, DetailedWalletStatsDocument, EventScopedFilterPredictionMarketsDocument, FilterExchangesDocument, FilterLaunchpadsDocument, FilterNetworksDocument, FilterPairsDocument, FilterPredictionEventsDocument, FilterPredictionMarketsDocument, FilterPredictionTraderMarketsDocument, FilterPredictionTradersDocument, FilterTokensDocument, FilterTokenWalletsDocument, FilterWalletsDocument, GetBarsDocument, GetCommunityNotesDocument, GetDetailedPairsStatsDocument, GetDetailedPairStatsDocument, GetDetailedTokenStatsDocument, GetEventLabelsDocument, GetExchangesDocument, GetNetworkConfigsDocument, GetNetworksDocument, GetNetworkStatsDocument, GetNetworkStatusDocument, GetSimulateTokenContractResultsDocument, GetSymbolDocument, GetTokenBarsDocument, GetTokenEventsDocument, GetTokenEventsForMakerDocument, GetTokenPricesDocument, GetWebhooksDocument, HoldersDocument, LiquidityLocksV2Document, LiquidityMetadataByTokenDocument, LiquidityMetadataDocument, ListPairsForTokenDocument, ListPairsWithMetadataForTokenDocument, PairMetadataDocument, PairsDocument, PredictionCategoriesDocument, PredictionEventBarsDocument, PredictionEventTopMarketsBarsDocument, PredictionMarketBarsDocument, PredictionMarketPriceDocument, PredictionMarketsDocument, PredictionOutcomeOrderBooksDocument, PredictionTokenHoldersDocument, PredictionTraderBarsDocument, PredictionTraderHoldingsDocument, PredictionTraderMarketsStatsDocument, PredictionTradersDocument, PredictionTradesDocument, TokenDocument, TokensDocument, TokenSparklinesDocument, TokenTopTradersDocument, TokenWalletStatsDocument, Top10HoldersPercentDocument, UsageDataDocument, WalletAggregateBackfillStateDocument, WalletChartDocument, WalletLabelTypesDocument, } from "./generated/graphql";
3
3
  export class Query {
4
4
  constructor(sdk) {
5
5
  this.sdk = sdk;
@@ -72,6 +72,7 @@ export class Query {
72
72
  this.tokenWalletStats = async (vars) => this.sdk.query(TokenWalletStatsDocument, vars);
73
73
  this.tokens = async (vars) => this.sdk.query(TokensDocument, vars);
74
74
  this.top10HoldersPercent = async (vars) => this.sdk.query(Top10HoldersPercentDocument, vars);
75
+ this.usageData = async (vars) => this.sdk.query(UsageDataDocument, vars);
75
76
  this.walletAggregateBackfillState = async (vars) => this.sdk.query(WalletAggregateBackfillStateDocument, vars);
76
77
  this.walletChart = async (vars) => this.sdk.query(WalletChartDocument, vars);
77
78
  this.walletLabelTypes = async (vars) => this.sdk.query(WalletLabelTypesDocument, vars);
@@ -1,23 +1,28 @@
1
1
  import { type Client, type ClientOptions, createClient, type Event, type EventListener, type ExecutionResult, type Sink, type SubscribePayload } from "graphql-ws";
2
2
  export { createClient };
3
3
  export declare const DEFAULT_EDGE_URL = "wss://fra.edge.codex.io/graphql";
4
+ export declare const ROBINHOOD_EDGE_URL = "wss://iad.edge.codex.io/graphql";
5
+ export declare function edgeUrlForNetwork(networkId: number): string;
4
6
  export interface SubscriptionOptions {
5
- /** Experimental: use edge for supported Solana streams whose commitments include Processed. */
7
+ /** Experimental: use edge for supported Solana or Robinhood streams whose commitments include Processed. */
6
8
  useEdge?: boolean;
7
9
  }
8
10
  export interface ClientWithEdge extends Client {
9
- /** Observe both transports, or select one with useEdge. */
11
+ /** Observe all transports, or select main/edge transports with useEdge. */
10
12
  on<E extends Event>(event: E, listener: EventListener<E>, options?: SubscriptionOptions): () => void;
11
13
  subscribe<Data = Record<string, unknown>, Extensions = unknown>(payload: SubscribePayload, sink: Sink<ExecutionResult<Data, Extensions>>, options?: SubscriptionOptions): () => void;
12
14
  }
13
15
  export interface EdgeClientOptions extends Omit<ClientOptions, "url"> {
14
- /** Defaults to the regional edge endpoint. */
16
+ /** Defaults to the Solana edge endpoint. Use ROBINHOOD_EDGE_URL for Robinhood. */
15
17
  url?: ClientOptions["url"];
16
18
  }
17
19
  /** Create a transport that connects only to edge. */
18
20
  export declare function createEdgeClient(options: EdgeClientOptions): Client;
19
21
  /** Snapshot and validate the arguments that will actually be sent to edge. */
20
- export declare function prepareEdgeSubscription(payload: SubscribePayload, replacer?: ClientOptions["jsonMessageReplacer"]): SubscribePayload;
22
+ export declare function prepareEdgeSubscription(payload: SubscribePayload, replacer?: ClientOptions["jsonMessageReplacer"]): {
23
+ payload: SubscribePayload;
24
+ networkId: number;
25
+ };
21
26
  /** Add per-subscription edge routing to an existing GraphQL client. */
22
27
  export declare function withEdge(main: Client, options: ClientOptions & {
23
28
  edgeUrl?: string;
package/dist/sdk/edge.js CHANGED
@@ -20,7 +20,8 @@ var __rest = (this && this.__rest) || function (s, e) {
20
20
  return t;
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.DEFAULT_EDGE_URL = exports.createClient = void 0;
23
+ exports.ROBINHOOD_EDGE_URL = exports.DEFAULT_EDGE_URL = exports.createClient = void 0;
24
+ exports.edgeUrlForNetwork = edgeUrlForNetwork;
24
25
  exports.createEdgeClient = createEdgeClient;
25
26
  exports.prepareEdgeSubscription = prepareEdgeSubscription;
26
27
  exports.withEdge = withEdge;
@@ -28,6 +29,12 @@ const graphql_ws_1 = require("graphql-ws");
28
29
  Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return graphql_ws_1.createClient; } });
29
30
  const edgeSubscription_1 = require("./edgeSubscription");
30
31
  exports.DEFAULT_EDGE_URL = "wss://fra.edge.codex.io/graphql";
32
+ exports.ROBINHOOD_EDGE_URL = "wss://iad.edge.codex.io/graphql";
33
+ function edgeUrlForNetwork(networkId) {
34
+ return networkId === edgeSubscription_1.ROBINHOOD_NETWORK_ID
35
+ ? exports.ROBINHOOD_EDGE_URL
36
+ : exports.DEFAULT_EDGE_URL;
37
+ }
31
38
  /** Create a transport that connects only to edge. */
32
39
  function createEdgeClient(options) {
33
40
  var _a;
@@ -36,12 +43,11 @@ function createEdgeClient(options) {
36
43
  /** Snapshot and validate the arguments that will actually be sent to edge. */
37
44
  function prepareEdgeSubscription(payload, replacer) {
38
45
  const snapshot = JSON.parse(JSON.stringify(payload, replacer));
39
- (0, edgeSubscription_1.assertEdgeSubscription)(snapshot);
40
- return snapshot;
46
+ return { payload: snapshot, networkId: (0, edgeSubscription_1.assertEdgeSubscription)(snapshot) };
41
47
  }
42
48
  /** Add per-subscription edge routing to an existing GraphQL client. */
43
49
  function withEdge(main, options) {
44
- const { edgeUrl = exports.DEFAULT_EDGE_URL } = options, wsOptions = __rest(options, ["edgeUrl"]);
50
+ const { edgeUrl } = options, wsOptions = __rest(options, ["edgeUrl"]);
45
51
  const mainHandlers = new Set();
46
52
  const edgeHandlers = new Set(wsOptions.on ? [wsOptions.on] : []);
47
53
  const handlersFor = (useEdge) => {
@@ -67,7 +73,7 @@ function withEdge(main, options) {
67
73
  main.on("message", mainEvents.message);
68
74
  main.on("closed", mainEvents.closed);
69
75
  main.on("error", mainEvents.error);
70
- let edge;
76
+ const edges = new Map();
71
77
  let disposed = false;
72
78
  return Object.assign(Object.assign({}, main), { on: (event, listener, subscriptionOptions = {}) => {
73
79
  const handlers = { [event]: listener };
@@ -85,12 +91,14 @@ function withEdge(main, options) {
85
91
  if (!subscriptionOptions.useEdge)
86
92
  return main.subscribe(payload, sink);
87
93
  // Reject before creating an edge client or opening any upstream operation.
88
- const snapshot = prepareEdgeSubscription(payload, wsOptions.jsonMessageReplacer);
94
+ const { payload: snapshot, networkId } = prepareEdgeSubscription(payload, wsOptions.jsonMessageReplacer);
95
+ const url = edgeUrl !== null && edgeUrl !== void 0 ? edgeUrl : edgeUrlForNetwork(networkId);
96
+ let edge = edges.get(url);
89
97
  if (!edge) {
90
98
  // Edge payloads are serialized once, before validation. Preserve custom
91
99
  // serialization for handshakes without transforming subscriptions again.
92
100
  let subscriptionMessage = false;
93
- edge = createEdgeClient(Object.assign(Object.assign({}, wsOptions), { url: edgeUrl, on: handlersFor(true), jsonMessageReplacer: function (key, value) {
101
+ edge = createEdgeClient(Object.assign(Object.assign({}, wsOptions), { url, on: handlersFor(true), jsonMessageReplacer: function (key, value) {
94
102
  if (key === "")
95
103
  subscriptionMessage = (value === null || value === void 0 ? void 0 : value.type) === "subscribe";
96
104
  return subscriptionMessage
@@ -99,13 +107,17 @@ function withEdge(main, options) {
99
107
  ? wsOptions.jsonMessageReplacer.call(this, key, value)
100
108
  : value;
101
109
  } }));
110
+ edges.set(url, edge);
102
111
  }
103
112
  return edge.subscribe(snapshot, sink);
104
113
  }, terminate: () => {
105
114
  main.terminate();
106
- edge === null || edge === void 0 ? void 0 : edge.terminate();
115
+ edges.forEach((edge) => edge.terminate());
107
116
  }, dispose: () => __awaiter(this, void 0, void 0, function* () {
108
117
  disposed = true;
109
- yield Promise.all([main.dispose(), edge === null || edge === void 0 ? void 0 : edge.dispose()]);
118
+ yield Promise.all([
119
+ main.dispose(),
120
+ ...Array.from(edges.values(), (edge) => edge.dispose()),
121
+ ]);
110
122
  }) });
111
123
  }
package/dist/sdk/edge.mjs CHANGED
@@ -1,7 +1,13 @@
1
1
  import { createClient, } from "graphql-ws";
2
- import { assertEdgeSubscription } from "./edgeSubscription";
2
+ import { assertEdgeSubscription, ROBINHOOD_NETWORK_ID, } from "./edgeSubscription";
3
3
  export { createClient };
4
4
  export const DEFAULT_EDGE_URL = "wss://fra.edge.codex.io/graphql";
5
+ export const ROBINHOOD_EDGE_URL = "wss://iad.edge.codex.io/graphql";
6
+ export function edgeUrlForNetwork(networkId) {
7
+ return networkId === ROBINHOOD_NETWORK_ID
8
+ ? ROBINHOOD_EDGE_URL
9
+ : DEFAULT_EDGE_URL;
10
+ }
5
11
  /** Create a transport that connects only to edge. */
6
12
  export function createEdgeClient(options) {
7
13
  return createClient({ ...options, url: options.url ?? DEFAULT_EDGE_URL });
@@ -9,12 +15,11 @@ export function createEdgeClient(options) {
9
15
  /** Snapshot and validate the arguments that will actually be sent to edge. */
10
16
  export function prepareEdgeSubscription(payload, replacer) {
11
17
  const snapshot = JSON.parse(JSON.stringify(payload, replacer));
12
- assertEdgeSubscription(snapshot);
13
- return snapshot;
18
+ return { payload: snapshot, networkId: assertEdgeSubscription(snapshot) };
14
19
  }
15
20
  /** Add per-subscription edge routing to an existing GraphQL client. */
16
21
  export function withEdge(main, options) {
17
- const { edgeUrl = DEFAULT_EDGE_URL, ...wsOptions } = options;
22
+ const { edgeUrl, ...wsOptions } = options;
18
23
  const mainHandlers = new Set();
19
24
  const edgeHandlers = new Set(wsOptions.on ? [wsOptions.on] : []);
20
25
  const handlersFor = (useEdge) => {
@@ -40,7 +45,7 @@ export function withEdge(main, options) {
40
45
  main.on("message", mainEvents.message);
41
46
  main.on("closed", mainEvents.closed);
42
47
  main.on("error", mainEvents.error);
43
- let edge;
48
+ const edges = new Map();
44
49
  let disposed = false;
45
50
  return {
46
51
  ...main,
@@ -61,14 +66,16 @@ export function withEdge(main, options) {
61
66
  if (!subscriptionOptions.useEdge)
62
67
  return main.subscribe(payload, sink);
63
68
  // Reject before creating an edge client or opening any upstream operation.
64
- const snapshot = prepareEdgeSubscription(payload, wsOptions.jsonMessageReplacer);
69
+ const { payload: snapshot, networkId } = prepareEdgeSubscription(payload, wsOptions.jsonMessageReplacer);
70
+ const url = edgeUrl ?? edgeUrlForNetwork(networkId);
71
+ let edge = edges.get(url);
65
72
  if (!edge) {
66
73
  // Edge payloads are serialized once, before validation. Preserve custom
67
74
  // serialization for handshakes without transforming subscriptions again.
68
75
  let subscriptionMessage = false;
69
76
  edge = createEdgeClient({
70
77
  ...wsOptions,
71
- url: edgeUrl,
78
+ url,
72
79
  on: handlersFor(true),
73
80
  jsonMessageReplacer: function (key, value) {
74
81
  if (key === "")
@@ -80,16 +87,20 @@ export function withEdge(main, options) {
80
87
  : value;
81
88
  },
82
89
  });
90
+ edges.set(url, edge);
83
91
  }
84
92
  return edge.subscribe(snapshot, sink);
85
93
  },
86
94
  terminate: () => {
87
95
  main.terminate();
88
- edge?.terminate();
96
+ edges.forEach((edge) => edge.terminate());
89
97
  },
90
98
  dispose: async () => {
91
99
  disposed = true;
92
- await Promise.all([main.dispose(), edge?.dispose()]);
100
+ await Promise.all([
101
+ main.dispose(),
102
+ ...Array.from(edges.values(), (edge) => edge.dispose()),
103
+ ]);
93
104
  },
94
105
  };
95
106
  }
@@ -1,3 +1,4 @@
1
1
  import type { SubscribePayload } from "graphql-ws";
2
- /** Validate the actual GraphQL arguments, including literals and variable defaults. */
3
- export declare function assertEdgeSubscription(payload: SubscribePayload): void;
2
+ export declare const ROBINHOOD_NETWORK_ID = 4663;
3
+ /** Validate GraphQL arguments, including literals and defaults, and return the target network. */
4
+ export declare function assertEdgeSubscription(payload: SubscribePayload): number;
@@ -1,19 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ROBINHOOD_NETWORK_ID = void 0;
3
4
  exports.assertEdgeSubscription = assertEdgeSubscription;
4
5
  const graphql_1 = require("graphql");
5
6
  const SOLANA_NETWORK_ID = 1399811149;
7
+ exports.ROBINHOOD_NETWORK_ID = 4663;
6
8
  const SUPPORTED_OPERATIONS = new Set([
7
9
  "onEventsCreated",
8
10
  "onTokenEventsCreated",
9
11
  "onBarsUpdated",
10
12
  "onTokenBarsUpdated",
11
13
  ]);
12
- /** Validate the actual GraphQL arguments, including literals and variable defaults. */
14
+ /** Validate GraphQL arguments, including literals and defaults, and return the target network. */
13
15
  function assertEdgeSubscription(payload) {
14
16
  var _a, _b, _c;
15
17
  function fail() {
16
- throw new Error("useEdge requires a supported Solana subscription with commitmentLevel including Processed");
18
+ throw new Error("useEdge requires a supported Solana or Robinhood subscription with commitmentLevel including Processed");
17
19
  }
18
20
  const document = (0, graphql_1.parse)(payload.query);
19
21
  const operation = (0, graphql_1.getOperationAST)(document, payload.operationName);
@@ -66,11 +68,13 @@ function assertEdgeSubscription(payload) {
66
68
  }
67
69
  };
68
70
  collect(args);
69
- if (!networks.length ||
70
- networks.some((network) => network !== SOLANA_NETWORK_ID))
71
+ const networkId = networks[0];
72
+ if ((networkId !== SOLANA_NETWORK_ID && networkId !== exports.ROBINHOOD_NETWORK_ID) ||
73
+ networks.some((network) => network !== networkId))
71
74
  fail();
72
75
  // Without an explicit quote, edge proxies this request back to Oregon.
73
76
  if (field.name.value === "onBarsUpdated" && args.quoteToken == null) {
74
77
  throw new Error("useEdge onBarsUpdated requires an explicit quoteToken");
75
78
  }
79
+ return networkId;
76
80
  }
@@ -1,15 +1,16 @@
1
1
  import { getOperationAST, Kind, parse, valueFromASTUntyped } from "graphql";
2
2
  const SOLANA_NETWORK_ID = 1399811149;
3
+ export const ROBINHOOD_NETWORK_ID = 4663;
3
4
  const SUPPORTED_OPERATIONS = new Set([
4
5
  "onEventsCreated",
5
6
  "onTokenEventsCreated",
6
7
  "onBarsUpdated",
7
8
  "onTokenBarsUpdated",
8
9
  ]);
9
- /** Validate the actual GraphQL arguments, including literals and variable defaults. */
10
+ /** Validate GraphQL arguments, including literals and defaults, and return the target network. */
10
11
  export function assertEdgeSubscription(payload) {
11
12
  function fail() {
12
- throw new Error("useEdge requires a supported Solana subscription with commitmentLevel including Processed");
13
+ throw new Error("useEdge requires a supported Solana or Robinhood subscription with commitmentLevel including Processed");
13
14
  }
14
15
  const document = parse(payload.query);
15
16
  const operation = getOperationAST(document, payload.operationName);
@@ -62,11 +63,13 @@ export function assertEdgeSubscription(payload) {
62
63
  }
63
64
  };
64
65
  collect(args);
65
- if (!networks.length ||
66
- networks.some((network) => network !== SOLANA_NETWORK_ID))
66
+ const networkId = networks[0];
67
+ if ((networkId !== SOLANA_NETWORK_ID && networkId !== ROBINHOOD_NETWORK_ID) ||
68
+ networks.some((network) => network !== networkId))
67
69
  fail();
68
70
  // Without an explicit quote, edge proxies this request back to Oregon.
69
71
  if (field.name.value === "onBarsUpdated" && args.quoteToken == null) {
70
72
  throw new Error("useEdge onBarsUpdated requires an explicit quoteToken");
71
73
  }
74
+ return networkId;
72
75
  }