@codex-data/sdk 2.4.11 → 2.5.1

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.
@@ -21,7 +21,7 @@ export declare class Codex {
21
21
  private apiConfig?;
22
22
  private client;
23
23
  private wsClient;
24
- private edgeWsClient;
24
+ private edgeWsClients;
25
25
  private disposed;
26
26
  queries: Query;
27
27
  mutations: Mutation;
package/dist/sdk/index.js CHANGED
@@ -35,6 +35,7 @@ class Codex {
35
35
  var _a, _b;
36
36
  this.apiKey = apiKey;
37
37
  this.apiConfig = apiConfig;
38
+ this.edgeWsClients = new Map();
38
39
  this.disposed = false;
39
40
  const config = this.parseConfig((_a = this.apiConfig) !== null && _a !== void 0 ? _a : {});
40
41
  this.queries = new Query_1.Query(this);
@@ -86,9 +87,9 @@ class Codex {
86
87
  updateConfig(incomingConfig) {
87
88
  var _a, _b, _c;
88
89
  // If we have an existing websocket connection, dispose of it.
89
- if (this.wsClient || this.edgeWsClient)
90
+ if (this.wsClient || this.edgeWsClients.size)
90
91
  void this.dispose();
91
- this.edgeWsClient = undefined;
92
+ this.edgeWsClients.clear();
92
93
  this.disposed = false;
93
94
  this.apiConfig = Object.assign(Object.assign({}, this.apiConfig), incomingConfig);
94
95
  // Merge the incoming config with the existing config.
@@ -114,9 +115,12 @@ class Codex {
114
115
  */
115
116
  dispose() {
116
117
  return __awaiter(this, void 0, void 0, function* () {
117
- var _a, _b;
118
+ var _a;
118
119
  this.disposed = true;
119
- yield Promise.all([(_a = this.wsClient) === null || _a === void 0 ? void 0 : _a.dispose(), (_b = this.edgeWsClient) === null || _b === void 0 ? void 0 : _b.dispose()]);
120
+ yield Promise.all([
121
+ (_a = this.wsClient) === null || _a === void 0 ? void 0 : _a.dispose(),
122
+ ...Array.from(this.edgeWsClients.values(), (edge) => edge.dispose()),
123
+ ]);
120
124
  });
121
125
  }
122
126
  /**
@@ -163,7 +167,7 @@ class Codex {
163
167
  * @returns A cleanup function to unsubscribe from the subscription.
164
168
  */
165
169
  subscribe(doc, args, sink, options) {
166
- var _a;
170
+ var _a, _b;
167
171
  if (!this.wsClient) {
168
172
  throw new Error("Websocket is not enabled in the config");
169
173
  }
@@ -173,15 +177,18 @@ class Codex {
173
177
  if (!(options === null || options === void 0 ? void 0 : options.useEdge))
174
178
  return this.wsClient.subscribe(payload, sink);
175
179
  // Validate before creating the edge transport or starting an operation.
176
- const snapshot = (0, edge_1.prepareEdgeSubscription)(payload);
177
- if (!this.edgeWsClient) {
178
- const config = this.parseConfig((_a = this.apiConfig) !== null && _a !== void 0 ? _a : {});
179
- this.edgeWsClient = (0, edge_1.createEdgeClient)(Object.assign(Object.assign({}, this.websocketOptions(config)), { url: config.apiEdgeUrl }));
180
- this.edgeWsClient.on("error", (error) => {
180
+ const { payload: snapshot, networkId } = (0, edge_1.prepareEdgeSubscription)(payload);
181
+ const config = this.parseConfig((_a = this.apiConfig) !== null && _a !== void 0 ? _a : {});
182
+ const url = (_b = config.apiEdgeUrl) !== null && _b !== void 0 ? _b : (0, edge_1.edgeUrlForNetwork)(networkId);
183
+ let edge = this.edgeWsClients.get(url);
184
+ if (!edge) {
185
+ edge = (0, edge_1.createEdgeClient)(Object.assign(Object.assign({}, this.websocketOptions(config)), { url }));
186
+ edge.on("error", (error) => {
181
187
  console.error("Websocket error: ", error);
182
188
  });
189
+ this.edgeWsClients.set(url, edge);
183
190
  }
184
- return this.edgeWsClient.subscribe(snapshot, sink);
191
+ return edge.subscribe(snapshot, sink);
185
192
  }
186
193
  }
187
194
  exports.Codex = Codex;
@@ -1,7 +1,7 @@
1
1
  import { GraphQLClient } from "graphql-request";
2
2
  import { createClient, } from "graphql-ws";
3
3
  import WebSocket from "isomorphic-ws";
4
- import { createEdgeClient, prepareEdgeSubscription, } from "./edge";
4
+ import { createEdgeClient, edgeUrlForNetwork, prepareEdgeSubscription, } from "./edge";
5
5
  import { invariant } from "./invariant";
6
6
  import { Mutation } from "./Mutation";
7
7
  import { Query } from "./Query";
@@ -19,6 +19,7 @@ export class Codex {
19
19
  constructor(apiKey, apiConfig) {
20
20
  this.apiKey = apiKey;
21
21
  this.apiConfig = apiConfig;
22
+ this.edgeWsClients = new Map();
22
23
  this.disposed = false;
23
24
  const config = this.parseConfig(this.apiConfig ?? {});
24
25
  this.queries = new Query(this);
@@ -77,9 +78,9 @@ export class Codex {
77
78
  */
78
79
  updateConfig(incomingConfig) {
79
80
  // If we have an existing websocket connection, dispose of it.
80
- if (this.wsClient || this.edgeWsClient)
81
+ if (this.wsClient || this.edgeWsClients.size)
81
82
  void this.dispose();
82
- this.edgeWsClient = undefined;
83
+ this.edgeWsClients.clear();
83
84
  this.disposed = false;
84
85
  this.apiConfig = { ...this.apiConfig, ...incomingConfig };
85
86
  // Merge the incoming config with the existing config.
@@ -105,7 +106,10 @@ export class Codex {
105
106
  */
106
107
  async dispose() {
107
108
  this.disposed = true;
108
- await Promise.all([this.wsClient?.dispose(), this.edgeWsClient?.dispose()]);
109
+ await Promise.all([
110
+ this.wsClient?.dispose(),
111
+ ...Array.from(this.edgeWsClients.values(), (edge) => edge.dispose()),
112
+ ]);
109
113
  }
110
114
  /**
111
115
  * This is the preferred way to execute queries.
@@ -154,17 +158,20 @@ export class Codex {
154
158
  if (!options?.useEdge)
155
159
  return this.wsClient.subscribe(payload, sink);
156
160
  // Validate before creating the edge transport or starting an operation.
157
- const snapshot = prepareEdgeSubscription(payload);
158
- if (!this.edgeWsClient) {
159
- const config = this.parseConfig(this.apiConfig ?? {});
160
- this.edgeWsClient = createEdgeClient({
161
+ const { payload: snapshot, networkId } = prepareEdgeSubscription(payload);
162
+ const config = this.parseConfig(this.apiConfig ?? {});
163
+ const url = config.apiEdgeUrl ?? edgeUrlForNetwork(networkId);
164
+ let edge = this.edgeWsClients.get(url);
165
+ if (!edge) {
166
+ edge = createEdgeClient({
161
167
  ...this.websocketOptions(config),
162
- url: config.apiEdgeUrl,
168
+ url,
163
169
  });
164
- this.edgeWsClient.on("error", (error) => {
170
+ edge.on("error", (error) => {
165
171
  console.error("Websocket error: ", error);
166
172
  });
173
+ this.edgeWsClients.set(url, edge);
167
174
  }
168
- return this.edgeWsClient.subscribe(snapshot, sink);
175
+ return edge.subscribe(snapshot, sink);
169
176
  }
170
177
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codex-data/sdk",
3
- "version": "2.4.11",
3
+ "version": "2.5.1",
4
4
  "engines": {
5
5
  "node": ">=17.5.0"
6
6
  },
package/schema.graphql CHANGED
@@ -937,6 +937,8 @@ type Query {
937
937
  walletChart(
938
938
  input: WalletChartInput!
939
939
  ): WalletChartResponse
940
+ """Returns the compute units charged for the request that carries this field, so you can see what a query costs before you run it at volume. Add it to any query; the field itself is free. `total` is the whole request; `items` lists each priced component. When the whole request was free (every root field errored), all values are zero."""
941
+ usageData: UsageData!
940
942
  """Returns the sniper, bundler and insider wallets that still hold a token, and how much of the supply they hold."""
941
943
  tokenWalletStats(
942
944
  input: TokenWalletStatsInput!
@@ -6504,6 +6506,20 @@ type SearchPredictionEvent {
6504
6506
  resolvedAt: Int
6505
6507
  }
6506
6508
 
6509
+ """The number of a prediction event's markets in each market status."""
6510
+ type PredictionEventMarketCounts {
6511
+ """Markets accepting trades."""
6512
+ open: Int!
6513
+ """Markets with trading temporarily halted. Not derived today, so always 0."""
6514
+ suspended: Int!
6515
+ """Markets whose outcome is determined or that are closed."""
6516
+ resolved: Int!
6517
+ """Markets that were invalidated. Not derived today, so always 0."""
6518
+ cancelled: Int!
6519
+ """Markets that have not opened yet."""
6520
+ pending: Int!
6521
+ }
6522
+
6507
6523
  """A prediction event matching a set of filter parameters."""
6508
6524
  type PredictionEventFilterResult {
6509
6525
  """The unique identifier."""
@@ -6540,6 +6556,8 @@ type PredictionEventFilterResult {
6540
6556
  markets: [PredictionEventFilterResultMarket!]!
6541
6557
  """Data for marketCount."""
6542
6558
  marketCount: Int!
6559
+ """The number of the event's markets in each status; the counts add up to marketCount. Null for events not reindexed since this field was added."""
6560
+ marketCounts: PredictionEventMarketCounts
6543
6561
  """Categories associated with this entity."""
6544
6562
  categories: [String!]!
6545
6563
  """The resolution source."""
@@ -9545,23 +9563,23 @@ type TokenFilterResult {
9545
9563
  swapPct1dOldWallet: String
9546
9564
  """The percentage of wallets that are less than 7d old that have traded in the last 24h"""
9547
9565
  swapPct7dOldWallet: String
9548
- """The number of wallets that have sniped the token"""
9566
+ """The number of wallets that have sniped the token. Null for a token without a launchpad; `tokenWalletStats` serves EVM ones."""
9549
9567
  sniperCount: Int
9550
- """The percentage of tokens held by snipers"""
9568
+ """The percentage of tokens held by snipers. Null for a token without a launchpad; `tokenWalletStats` serves EVM ones."""
9551
9569
  sniperHeldPercentage: Float
9552
- """The number of wallets that have bundled the token"""
9570
+ """The number of wallets that have bundled the token. Null for a token without a launchpad; `tokenWalletStats` serves EVM ones."""
9553
9571
  bundlerCount: Int
9554
- """The percentage of tokens held by bundlers"""
9572
+ """The percentage of tokens held by bundlers. Null for a token without a launchpad; `tokenWalletStats` serves EVM ones."""
9555
9573
  bundlerHeldPercentage: Float
9556
- """The number of wallets that have been an insider of the token"""
9574
+ """The number of wallets that have been an insider of the token. Null for a token without a launchpad; `tokenWalletStats` serves EVM ones."""
9557
9575
  insiderCount: Int
9558
- """The percentage of tokens held by insiders"""
9576
+ """The percentage of tokens held by insiders. Null for a token without a launchpad; `tokenWalletStats` serves EVM ones."""
9559
9577
  insiderHeldPercentage: Float
9560
- """The number of suspicious wallets (deduplicated union of snipers, bundlers, and insiders)"""
9578
+ """The number of suspicious wallets (deduplicated union of snipers, bundlers, and insiders). Null for a token without a launchpad; `tokenWalletStats` serves EVM ones."""
9561
9579
  suspiciousCount: Int
9562
- """The percentage of tokens held by suspicious wallets"""
9580
+ """The percentage of tokens held by suspicious wallets. Null for a token without a launchpad; `tokenWalletStats` serves EVM ones."""
9563
9581
  suspiciousHeldPercentage: Float
9564
- """The percentage of tokens held by the dev"""
9582
+ """The percentage of tokens held by the dev. Null for a token without a launchpad; `tokenWalletStats` serves EVM ones."""
9565
9583
  devHeldPercentage: Float
9566
9584
  """The percentage of total supply held by the top 10 holders."""
9567
9585
  top10HoldersPercent: Float
@@ -13205,23 +13223,23 @@ input TokenFilters {
13205
13223
  poolFees24: NumberFilter
13206
13224
  """Filter by fee to volume ratio in the past 24 hours."""
13207
13225
  feeToVolumeRatio24: NumberFilter
13208
- """Filter by number of wallets that have sniped the token"""
13226
+ """Filter by number of wallets that have sniped the token. Covers launchpad tokens only; any other token never matches."""
13209
13227
  sniperCount: NumberFilter
13210
- """Filter by percentage of tokens held by snipers"""
13228
+ """Filter by percentage of tokens held by snipers. Covers launchpad tokens only; any other token never matches."""
13211
13229
  sniperHeldPercentage: NumberFilter
13212
- """Filter by number of wallets that have bundled the token"""
13230
+ """Filter by number of wallets that have bundled the token. Covers launchpad tokens only; any other token never matches."""
13213
13231
  bundlerCount: NumberFilter
13214
- """Filter by percentage of tokens held by bundlers"""
13232
+ """Filter by percentage of tokens held by bundlers. Covers launchpad tokens only; any other token never matches."""
13215
13233
  bundlerHeldPercentage: NumberFilter
13216
- """Filter by number of wallets that have been an insider of the token"""
13234
+ """Filter by number of wallets that have been an insider of the token. Covers launchpad tokens only; any other token never matches."""
13217
13235
  insiderCount: NumberFilter
13218
- """Filter by percentage of tokens held by insiders"""
13236
+ """Filter by percentage of tokens held by insiders. Covers launchpad tokens only; any other token never matches."""
13219
13237
  insiderHeldPercentage: NumberFilter
13220
- """Filter by number of suspicious wallets (deduplicated union of snipers, bundlers, and insiders)"""
13238
+ """Filter by number of suspicious wallets (deduplicated union of snipers, bundlers, and insiders). Covers launchpad tokens only; any other token never matches."""
13221
13239
  suspiciousCount: NumberFilter
13222
- """Filter by percentage of tokens held by suspicious wallets"""
13240
+ """Filter by percentage of tokens held by suspicious wallets. Covers launchpad tokens only; any other token never matches."""
13223
13241
  suspiciousHeldPercentage: NumberFilter
13224
- """Filter by percentage of tokens held by the dev"""
13242
+ """Filter by percentage of tokens held by the dev. Covers launchpad tokens only; any other token never matches."""
13225
13243
  devHeldPercentage: NumberFilter
13226
13244
  """Filter by top 10 holders percentage."""
13227
13245
  top10HoldersPercent: NumberFilter
@@ -17324,6 +17342,36 @@ input WalletAggregateBackfillStateInput {
17324
17342
  walletAddress: String!
17325
17343
  }
17326
17344
 
17345
+ """Response returned by `usageData`: the compute units charged for the request that carried the field."""
17346
+ type UsageData {
17347
+ """Each priced component of the request: one entry per operation, per-object type, or priced field."""
17348
+ items: [UsageDataItem!]!
17349
+ """Totals across all items."""
17350
+ total: UsageDataMetrics!
17351
+ }
17352
+
17353
+ """Usage metrics for one priced component, or for the whole request. Values are integers returned as strings."""
17354
+ type UsageDataMetrics {
17355
+ """Billable units, not requests: 1 per call of a priced field, or the number of objects returned for a per-object cost."""
17356
+ count: String!
17357
+ """Response bytes measured for this component. Reported for reference; standard pricing does not bill it."""
17358
+ bytes: String!
17359
+ """Processing time in milliseconds measured for this component. Reported for reference; standard pricing does not bill it."""
17360
+ durationMs: String!
17361
+ """Compute units charged, with six decimals of precision: 1,000,000 = 1 CU."""
17362
+ computeUnits: String!
17363
+ }
17364
+
17365
+ """One priced component of a request."""
17366
+ type UsageDataItem {
17367
+ """The operation or field that was priced, for example `filterTokens` or `filterTokens.results.token`."""
17368
+ resource: String!
17369
+ """For a per-object cost, the type of the objects counted (for example `EnhancedToken`). Null for operation and field costs."""
17370
+ entityType: String
17371
+ """The metrics charged for this component."""
17372
+ metrics: UsageDataMetrics!
17373
+ }
17374
+
17327
17375
  """Input for `tokenWalletStats`."""
17328
17376
  input TokenWalletStatsInput {
17329
17377
  """The contract address of the token."""
@@ -17332,7 +17380,7 @@ input TokenWalletStatsInput {
17332
17380
  networkId: Int!
17333
17381
  }
17334
17382
 
17335
- """The sniper, bundler and insider wallets that still hold a token. Counts, amounts and addresses cover current holders only: a labelled wallet that has sold its whole balance is left out, so every figure falls as those wallets sell. Available for launchpad tokens on every network, and for EVM tokens without a launchpad that have a known creator and were created since 2025-10-08. Other tokens return zeros."""
17383
+ """The sniper, bundler and insider wallets that still hold a token. Counts, amounts and addresses cover current holders only: a labelled wallet that has sold its whole balance is left out, so every figure falls as those wallets sell. Each label reads at most 1,000 holders; past that, its count reads 1,000 and its amount and percentage cover those holders only. Available for launchpad tokens on every network, and for EVM tokens without a launchpad that have a known creator and were created since 2025-10-08. Read `covered` first: for any other token it is false, and every figure is 0 because nothing was measured."""
17336
17384
  type TokenWalletStats {
17337
17385
  """The ID of the token (`address:networkId`)."""
17338
17386
  tokenId: String!
@@ -17342,7 +17390,9 @@ type TokenWalletStats {
17342
17390
  networkId: Int!
17343
17391
  """The total supply of the token, unshifted. Every held percentage is measured against it."""
17344
17392
  tokenTotalSupply: String!
17345
- """The number of sniper wallets that hold this token. A sniper bought within the first 5 seconds of trading."""
17393
+ """Whether Codex tracks snipers, bundlers and insiders for this token. When false, every count and percentage is 0 because nothing was measured, not because none were found."""
17394
+ covered: Boolean!
17395
+ """The number of sniper wallets that hold this token. A sniper bought within the first 5 seconds of trading. The creator's own buy at launch counts."""
17346
17396
  sniperCount: Int!
17347
17397
  """The percentage of token supply held by sniper wallets."""
17348
17398
  sniperHeldPercentage: Float!
@@ -17350,7 +17400,7 @@ type TokenWalletStats {
17350
17400
  sniperAddresses: [String!]!
17351
17401
  """The amount of the token held by sniper wallets, unshifted."""
17352
17402
  sniperHeldAmount: String!
17353
- """The number of bundler wallets that hold this token. A bundler is one of 4 or more wallets that bought the token in the same block at launch."""
17403
+ """The number of bundler wallets that hold this token. A bundler is one of 4 or more wallets that bought the token in the same block while it was on its launchpad, or in its first hour when it has none. A wallet one sender bought a large share for, alongside other wallets in the same block, is a bundler too."""
17354
17404
  bundlerCount: Int!
17355
17405
  """The percentage of token supply held by bundler wallets."""
17356
17406
  bundlerHeldPercentage: Float!
@@ -17358,7 +17408,7 @@ type TokenWalletStats {
17358
17408
  bundlerAddresses: [String!]!
17359
17409
  """The amount of the token held by bundler wallets, unshifted."""
17360
17410
  bundlerHeldAmount: String!
17361
- """The number of insider wallets that hold this token. An insider received the token through a link to its creator rather than by buying it on the open market."""
17411
+ """The number of insider wallets that hold this token. An insider got the token through a link to its creator rather than by buying it on the open market: it bought in the creation transaction, received the token from the creator, or was first funded by the creator. On Solana, a wallet seeded with the token in its first minutes without buying it is an insider too."""
17362
17412
  insiderCount: Int!
17363
17413
  """The percentage of token supply held by insider wallets."""
17364
17414
  insiderHeldPercentage: Float!