@0xinsider/mcp 2.1.3 → 2.6.0

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.
Files changed (74) hide show
  1. package/README.md +33 -19
  2. package/dist/catalog.generated.d.ts +46 -10
  3. package/dist/catalog.generated.d.ts.map +1 -1
  4. package/dist/catalog.generated.js +55 -10
  5. package/dist/catalog.generated.js.map +1 -1
  6. package/dist/cli-lib.d.ts +7 -0
  7. package/dist/cli-lib.d.ts.map +1 -1
  8. package/dist/cli-lib.js +83 -17
  9. package/dist/cli-lib.js.map +1 -1
  10. package/dist/client.d.ts +2 -0
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js.map +1 -1
  13. package/dist/constants.d.ts +1 -1
  14. package/dist/constants.js +1 -1
  15. package/dist/product-cli/index.d.ts.map +1 -1
  16. package/dist/product-cli/index.js +3 -1
  17. package/dist/product-cli/index.js.map +1 -1
  18. package/dist/prompts/index.d.ts.map +1 -1
  19. package/dist/prompts/index.js +38 -24
  20. package/dist/prompts/index.js.map +1 -1
  21. package/dist/sdk/client.d.ts +242 -21
  22. package/dist/sdk/client.d.ts.map +1 -1
  23. package/dist/sdk/client.js +371 -16
  24. package/dist/sdk/client.js.map +1 -1
  25. package/dist/sdk/errors.d.ts +21 -1
  26. package/dist/sdk/errors.d.ts.map +1 -1
  27. package/dist/sdk/errors.js +46 -1
  28. package/dist/sdk/errors.js.map +1 -1
  29. package/dist/sdk/index.d.ts +35 -5
  30. package/dist/sdk/index.d.ts.map +1 -1
  31. package/dist/sdk/index.js +2 -2
  32. package/dist/sdk/index.js.map +1 -1
  33. package/dist/sdk/pagination.d.ts +7 -7
  34. package/dist/sdk/pagination.d.ts.map +1 -1
  35. package/dist/sdk/pagination.js.map +1 -1
  36. package/dist/sdk/schema.d.ts +1164 -314
  37. package/dist/sdk/schema.d.ts.map +1 -1
  38. package/dist/sdk/stream.d.ts +12 -7
  39. package/dist/sdk/stream.d.ts.map +1 -1
  40. package/dist/sdk/stream.js +82 -3
  41. package/dist/sdk/stream.js.map +1 -1
  42. package/dist/sdk/webhooks.d.ts +148 -12
  43. package/dist/sdk/webhooks.d.ts.map +1 -1
  44. package/dist/sdk/webhooks.js +25 -6
  45. package/dist/sdk/webhooks.js.map +1 -1
  46. package/dist/server.d.ts.map +1 -1
  47. package/dist/server.js +13 -2
  48. package/dist/server.js.map +1 -1
  49. package/dist/tools/games.d.ts +5 -0
  50. package/dist/tools/games.d.ts.map +1 -0
  51. package/dist/tools/games.js +103 -0
  52. package/dist/tools/games.js.map +1 -0
  53. package/dist/tools/get-insider-radar.d.ts.map +1 -1
  54. package/dist/tools/get-insider-radar.js +10 -32
  55. package/dist/tools/get-insider-radar.js.map +1 -1
  56. package/dist/tools/get-leaderboard.d.ts.map +1 -1
  57. package/dist/tools/get-leaderboard.js +20 -2
  58. package/dist/tools/get-leaderboard.js.map +1 -1
  59. package/dist/tools/get-market-intel.js +2 -2
  60. package/dist/tools/get-market-intel.js.map +1 -1
  61. package/dist/tools/get-suspicious-trades.d.ts +26 -0
  62. package/dist/tools/get-suspicious-trades.d.ts.map +1 -0
  63. package/dist/tools/get-suspicious-trades.js +91 -0
  64. package/dist/tools/get-suspicious-trades.js.map +1 -0
  65. package/dist/tools/get-whale-trades.d.ts +2 -0
  66. package/dist/tools/get-whale-trades.d.ts.map +1 -1
  67. package/dist/tools/get-whale-trades.js +18 -6
  68. package/dist/tools/get-whale-trades.js.map +1 -1
  69. package/dist/tools/pick-of-the-day.js +1 -1
  70. package/dist/tools/read-parity.d.ts +9 -1
  71. package/dist/tools/read-parity.d.ts.map +1 -1
  72. package/dist/tools/read-parity.js +109 -50
  73. package/dist/tools/read-parity.js.map +1 -1
  74. package/package.json +1 -1
@@ -19,7 +19,8 @@
19
19
  * - Extra typed convenience methods for list/candle/webhook-event/stream
20
20
  * surfaces and a typed `Grade` enum.
21
21
  */
22
- import { errorFromResponse, OxinsiderApiError, InvalidResponseError, RequestTimeoutError, } from "./errors.js";
22
+ import { createHash } from "node:crypto";
23
+ import { errorFromResponse, ExportIntegrityError, OxinsiderApiError, InvalidResponseError, RequestTimeoutError, } from "./errors.js";
23
24
  import { RETRY_AFTER_CEILING_MS, retryAfterSeconds, sleepUnlessAborted, } from "./retry.js";
24
25
  /**
25
26
  * The full V1 operation table. One row per OpenAPI operation with a
@@ -119,6 +120,12 @@ export const API_CLIENT_OPERATIONS = [
119
120
  operationId: "getTraderExportStatus",
120
121
  auth: "bearer",
121
122
  },
123
+ {
124
+ method: "POST",
125
+ path: "/api/v1/trader/{address}/export/cancel",
126
+ operationId: "cancelTraderExport",
127
+ auth: "bearer",
128
+ },
122
129
  {
123
130
  method: "GET",
124
131
  path: "/api/v1/leaderboard/trending",
@@ -128,6 +135,18 @@ export const API_CLIENT_OPERATIONS = [
128
135
  // Pre-existing gap, fixed here (#7209): the route has shipped in openapi.json,
129
136
  // llms-full.txt, agents.md, and the discovery doc, but never in the SDK table --
130
137
  // so `drift.test.ts` was RED on main and SDK users had no typed method for it.
138
+ {
139
+ method: "GET",
140
+ path: "/api/v1/sports/pre-game-sides",
141
+ operationId: "listPreGameSides",
142
+ auth: "bearer",
143
+ },
144
+ {
145
+ method: "GET",
146
+ path: "/api/v1/sports/pre-game-side-observations",
147
+ operationId: "listPreGameSideObservations",
148
+ auth: "bearer",
149
+ },
131
150
  {
132
151
  method: "GET",
133
152
  path: "/api/v1/sports-edge-signals",
@@ -140,6 +159,48 @@ export const API_CLIENT_OPERATIONS = [
140
159
  operationId: "listSportsEdgeObservations",
141
160
  auth: "bearer",
142
161
  },
162
+ {
163
+ method: "GET",
164
+ path: "/api/v1/games",
165
+ operationId: "listGames",
166
+ auth: "bearer",
167
+ },
168
+ {
169
+ method: "GET",
170
+ path: "/api/v1/games/{event_slug}",
171
+ operationId: "getGame",
172
+ auth: "bearer",
173
+ },
174
+ {
175
+ method: "GET",
176
+ path: "/api/v1/large-trades",
177
+ operationId: "listLargeTrades",
178
+ auth: "bearer",
179
+ },
180
+ {
181
+ method: "GET",
182
+ path: "/api/v1/large-trades/history",
183
+ operationId: "listLargeTradeHistory",
184
+ auth: "bearer",
185
+ },
186
+ {
187
+ method: "GET",
188
+ path: "/api/v1/large-trades/{id}/counterparties/executions",
189
+ operationId: "listLargeTradeCounterpartyExecutions",
190
+ auth: "bearer",
191
+ },
192
+ {
193
+ method: "GET",
194
+ path: "/api/v1/large-trades/{id}/counterparties/executions/{execution_id}/makers",
195
+ operationId: "listLargeTradeCounterpartyMakers",
196
+ auth: "bearer",
197
+ },
198
+ {
199
+ method: "GET",
200
+ path: "/api/v1/large-trades/{id}",
201
+ operationId: "getLargeTrade",
202
+ auth: "bearer",
203
+ },
143
204
  {
144
205
  method: "GET",
145
206
  path: "/api/v1/whale-trades",
@@ -249,6 +310,22 @@ export const API_CLIENT_OPERATIONS = [
249
310
  operationId: "getMarketCandles",
250
311
  auth: "bearer",
251
312
  },
313
+ {
314
+ method: "GET",
315
+ path: "/api/v1/suspicious-trades",
316
+ operationId: "listSuspiciousTrades",
317
+ auth: "bearer",
318
+ },
319
+ {
320
+ method: "GET",
321
+ path: "/api/v1/suspicious-trades/{id}",
322
+ operationId: "getSuspiciousTrade",
323
+ auth: "bearer",
324
+ },
325
+ // Deprecated aliases (#16301). Both paths stay live with no retirement
326
+ // date; responses carry Deprecation and a Link rel="successor-version".
327
+ // `/api/v1/insider-radar/{id}` also keeps answering `object: "radar_flag"`,
328
+ // so these entries are what an existing integration must keep exercising.
252
329
  {
253
330
  method: "GET",
254
331
  path: "/api/v1/insider-radar",
@@ -502,11 +579,26 @@ export const READ_ONLY_POST_OPERATIONS = [
502
579
  "batchGetTraders",
503
580
  "batchGetMarketIntel",
504
581
  ];
582
+ /**
583
+ * Writes whose repeat converges on the state the first one reached, so a
584
+ * retry cannot repeat a side effect and needs no `Idempotency-Key` (#16254).
585
+ * `POST /api/v1/trader/{address}/export/cancel` moves a job at most once and
586
+ * answers its current state every time: a second cancel of a cancelled job
587
+ * returns it unchanged, and a cancel that lost the race to a finished file
588
+ * returns the ready job. They are retried like a read; the API does not read
589
+ * an `Idempotency-Key` on them, so one is refused like on any other write.
590
+ */
591
+ export const CONVERGENT_WRITE_OPERATIONS = [
592
+ "cancelTraderExport",
593
+ ];
505
594
  const idempotentWrites = new Set(IDEMPOTENT_WRITE_OPERATIONS);
506
595
  const readOnlyPosts = new Set(READ_ONLY_POST_OPERATIONS);
596
+ const convergentWrites = new Set(CONVERGENT_WRITE_OPERATIONS);
507
597
  /** The retry class of an operation; see `RetryEligibility`. */
508
598
  export function retryEligibility(operation) {
509
- if (operation.method === "GET" || readOnlyPosts.has(operation.operationId)) {
599
+ if (operation.method === "GET" ||
600
+ readOnlyPosts.has(operation.operationId) ||
601
+ convergentWrites.has(operation.operationId)) {
510
602
  return "read";
511
603
  }
512
604
  return idempotentWrites.has(operation.operationId) ? "keyed" : "never";
@@ -522,8 +614,11 @@ export const DEFAULT_BASE_URL = "https://api.0xinsider.com";
522
614
  * The sandbox server, the second `servers` entry of the OpenAPI document: no
523
615
  * credential, no production data, every documented operation answered with
524
616
  * its example or a deterministic sample, `?sandbox_status=<code>` for a
525
- * documented error, and `X-Oxi-Sandbox: true` on every response. Streams and
526
- * file downloads are not simulated there and answer 400.
617
+ * documented error, and `X-Oxi-Sandbox: true` on every response. The two
618
+ * Markdown documents answer `200 text/markdown` there and the export download
619
+ * answers its `302` to a sample file the sandbox serves itself. `GET
620
+ * /api/v1/stream` is the one operation it does not simulate and answers 400,
621
+ * because an SSE stream is a live connection rather than a body.
527
622
  */
528
623
  export const SANDBOX_BASE_URL = "https://0xinsider.com/sandbox";
529
624
  /** A live secret key starts with this; the sandbox never needs one. */
@@ -651,6 +746,101 @@ function composeRequestSignal(timeoutMs, caller) {
651
746
  }
652
747
  return { signal: controller.signal, dispose };
653
748
  }
749
+ /**
750
+ * `response` with `dispose` deferred to the end of its body: the stream's
751
+ * close, error or cancellation (#16686). Without a `dispose` (a runtime with
752
+ * `AbortSignal.any`, or no composition) the response is returned as is.
753
+ */
754
+ function releaseWhenBodySettles(response, dispose) {
755
+ if (!dispose)
756
+ return response;
757
+ if (!response.body) {
758
+ dispose();
759
+ return response;
760
+ }
761
+ const reader = response.body.getReader();
762
+ const body = new ReadableStream({
763
+ async pull(controller) {
764
+ try {
765
+ const { done, value } = await reader.read();
766
+ if (done) {
767
+ dispose();
768
+ controller.close();
769
+ return;
770
+ }
771
+ controller.enqueue(value);
772
+ }
773
+ catch (error) {
774
+ dispose();
775
+ controller.error(error);
776
+ }
777
+ },
778
+ cancel(reason) {
779
+ dispose();
780
+ return reader.cancel(reason);
781
+ },
782
+ });
783
+ return new Response(body, {
784
+ status: response.status,
785
+ statusText: response.statusText,
786
+ headers: response.headers,
787
+ });
788
+ }
789
+ /**
790
+ * Hash the bytes a caller actually receives while preserving streaming. The
791
+ * object is gzip encoded at rest, but fetch exposes the decoded content stream
792
+ * to Node callers, which is the byte domain covered by content_sha256.
793
+ */
794
+ function verifyExportBody(response, jobId, expectedSha256, expectedSizeBytes) {
795
+ if (!response.body) {
796
+ throw new ExportIntegrityError(jobId, expectedSha256, null, expectedSizeBytes, 0);
797
+ }
798
+ const reader = response.body.getReader();
799
+ const hasher = createHash("sha256");
800
+ let actualSizeBytes = 0;
801
+ const body = new ReadableStream({
802
+ async pull(controller) {
803
+ try {
804
+ const { done, value } = await reader.read();
805
+ if (done) {
806
+ const actualSha256 = hasher.digest("hex");
807
+ if (actualSizeBytes !== expectedSizeBytes ||
808
+ actualSha256 !== expectedSha256) {
809
+ controller.error(new ExportIntegrityError(jobId, expectedSha256, actualSha256, expectedSizeBytes, actualSizeBytes));
810
+ return;
811
+ }
812
+ controller.close();
813
+ return;
814
+ }
815
+ if (value === undefined) {
816
+ controller.error(new ExportIntegrityError(jobId, expectedSha256, null, expectedSizeBytes, actualSizeBytes));
817
+ return;
818
+ }
819
+ hasher.update(value);
820
+ actualSizeBytes += value.byteLength;
821
+ controller.enqueue(value);
822
+ }
823
+ catch (error) {
824
+ controller.error(new ExportIntegrityError(jobId, expectedSha256, null, expectedSizeBytes, actualSizeBytes, error));
825
+ }
826
+ },
827
+ cancel(reason) {
828
+ return reader.cancel(reason);
829
+ },
830
+ });
831
+ return new Response(body, {
832
+ status: response.status,
833
+ statusText: response.statusText,
834
+ headers: response.headers,
835
+ });
836
+ }
837
+ /** JSON-RPC methods `POST /api/v1/mcp` answers without a credential. */
838
+ function isKeylessMcpMethod(method) {
839
+ return (method === "initialize" ||
840
+ method === "ping" ||
841
+ method === "tools/list" ||
842
+ method.startsWith("notifications/"));
843
+ }
654
844
  function isTimeoutAbort(error) {
655
845
  return (typeof error === "object" &&
656
846
  error !== null &&
@@ -861,7 +1051,11 @@ export class OxinsiderApiClient {
861
1051
  * listed.response?.result;
862
1052
  */
863
1053
  async mcp(request, options = {}) {
864
- const operation = this.resolveOperation("createMcpJsonRpcResponse", "jsonrpc");
1054
+ // `initialize`, `ping`, `tools/list` and the notifications need no
1055
+ // credential (`backend/src/mcp/mod.rs`); only `tools/call` does, so the
1056
+ // local credential check is per method (#16686). A configured key is
1057
+ // still sent on every method.
1058
+ const operation = this.resolveOperation("createMcpJsonRpcResponse", "jsonrpc", !isKeylessMcpMethod(request.method));
865
1059
  const { sessionId, protocolVersion, ...transportOptions } = options;
866
1060
  const headers = { ...options.headers };
867
1061
  if (sessionId !== undefined) {
@@ -870,7 +1064,9 @@ export class OxinsiderApiClient {
870
1064
  if (protocolVersion !== undefined) {
871
1065
  headers["mcp-protocol-version"] = protocolVersion;
872
1066
  }
873
- const body = { jsonrpc: "2.0", ...request };
1067
+ // Set after the spread: an explicit `jsonrpc: undefined` would otherwise
1068
+ // drop the field and the server would answer 400 (#16686).
1069
+ const body = { ...request, jsonrpc: "2.0" };
874
1070
  return this.request(operation, { ...transportOptions, headers, body, maxRetries: 0 }, async (response) => {
875
1071
  const sessionId = response.headers.get("mcp-session-id");
876
1072
  const result = {
@@ -888,6 +1084,18 @@ export class OxinsiderApiClient {
888
1084
  return result;
889
1085
  });
890
1086
  }
1087
+ /**
1088
+ * Read the owner-authorized lifecycle and artifact manifest for one export
1089
+ * job. The manifest is immutable for the artifact; the download URL remains
1090
+ * temporary and is resolved separately.
1091
+ */
1092
+ getTraderExportStatus(address, jobId, options = {}) {
1093
+ return this.call("getTraderExportStatus", {
1094
+ ...options,
1095
+ path: { address },
1096
+ query: { job_id: jobId },
1097
+ });
1098
+ }
891
1099
  /**
892
1100
  * Resolve the presigned object URL behind `GET /api/v1/trader/{address}/export/download`
893
1101
  * without downloading anything (#16137).
@@ -941,8 +1149,20 @@ export class OxinsiderApiClient {
941
1149
  * await pipeline(Readable.fromWeb(response.body), createWriteStream(filename ?? "export.json"));
942
1150
  */
943
1151
  async downloadTraderExport(address, jobId, options = {}) {
944
- const target = await this.getTraderExportDownloadUrl(address, jobId, options);
945
- const downloadSignal = composeRequestSignal(options.downloadTimeoutMs ?? null, options.signal);
1152
+ const { verifyChecksum = false, downloadTimeoutMs, ...requestOptions } = options;
1153
+ let manifest = null;
1154
+ if (verifyChecksum) {
1155
+ const status = await this.getTraderExportStatus(address, jobId, requestOptions);
1156
+ if (isApiNotModifiedResponse(status)) {
1157
+ throw new InvalidResponseError(304, `Export job ${String(jobId)} status was not modified, so its manifest could not be verified. Omit If-None-Match when verifyChecksum is enabled.`, status);
1158
+ }
1159
+ if (status.data.status !== "ready" || !status.data.artifact?.manifest) {
1160
+ throw new InvalidResponseError(200, `Export job ${String(jobId)} did not return a ready artifact manifest, so verifyChecksum cannot verify the download. Wait for status=ready or request a fresh export.`, status);
1161
+ }
1162
+ manifest = status.data.artifact.manifest;
1163
+ }
1164
+ const target = await this.getTraderExportDownloadUrl(address, jobId, requestOptions);
1165
+ const downloadSignal = composeRequestSignal(downloadTimeoutMs ?? null, options.signal);
946
1166
  let response;
947
1167
  try {
948
1168
  // No headers, and no credentials: the presigned URL authorizes itself,
@@ -953,12 +1173,21 @@ export class OxinsiderApiClient {
953
1173
  signal: downloadSignal.signal,
954
1174
  });
955
1175
  }
956
- finally {
1176
+ catch (error) {
957
1177
  downloadSignal.dispose?.();
1178
+ throw error;
958
1179
  }
959
1180
  if (!response.ok) {
1181
+ downloadSignal.dispose?.();
960
1182
  throw new InvalidResponseError(response.status, `The presigned export URL answered ${response.status}. A presigned link is valid for about an hour; request a fresh one with getTraderExportDownloadUrl.`, null);
961
1183
  }
1184
+ // The caller reads the body after this returns, so the composed signal
1185
+ // (caller abort plus `downloadTimeoutMs`) stays wired until the body ends
1186
+ // or is cancelled, not only until the headers arrive (#16686).
1187
+ response = releaseWhenBodySettles(response, downloadSignal.dispose);
1188
+ if (manifest) {
1189
+ response = verifyExportBody(response, jobId, manifest.content_sha256, manifest.content_size_bytes);
1190
+ }
962
1191
  const contentLength = response.headers.get("content-length");
963
1192
  return {
964
1193
  ...target,
@@ -966,13 +1195,20 @@ export class OxinsiderApiClient {
966
1195
  contentLength: contentLength === null ? null : Number.parseInt(contentLength, 10),
967
1196
  contentType: response.headers.get("content-type"),
968
1197
  filename: filenameFromDisposition(response.headers.get("content-disposition")),
1198
+ integrity: manifest
1199
+ ? {
1200
+ algorithm: "sha256",
1201
+ expectedSha256: manifest.content_sha256,
1202
+ expectedSizeBytes: manifest.content_size_bytes,
1203
+ }
1204
+ : null,
969
1205
  };
970
1206
  }
971
1207
  /**
972
1208
  * Look up an operation and refuse it when the caller reached for the wrong
973
1209
  * reader (#16137): `call()` on a Markdown route used to fail as a bad 200.
974
1210
  */
975
- resolveOperation(operationId, expected) {
1211
+ resolveOperation(operationId, expected, requireCredential = true) {
976
1212
  const operation = operationsById.get(operationId);
977
1213
  if (!operation) {
978
1214
  throw new Error(`Unknown 0xinsider API operation: ${operationId}`);
@@ -983,7 +1219,7 @@ export class OxinsiderApiClient {
983
1219
  }
984
1220
  // The sandbox answers every operation without a credential; production
985
1221
  // does not, and the local check saves a round trip that can only be 401.
986
- if (operation.auth === "bearer" && !this.apiKey && !this.sandbox) {
1222
+ if (requireCredential && operation.auth === "bearer" && !this.apiKey && !this.sandbox) {
987
1223
  throw new Error(`${operationId} requires an API key (oxi_sk_*)`);
988
1224
  }
989
1225
  return operation;
@@ -1167,9 +1403,17 @@ export class OxinsiderApiClient {
1167
1403
  listTrendingWallets(params = {}, options = {}) {
1168
1404
  return this.list("listTrendingWallets", { ...options, query: params });
1169
1405
  }
1406
+ listLargeTrades(params = {}, options = {}) {
1407
+ return this.list("listLargeTrades", { ...options, query: params });
1408
+ }
1409
+ listLargeTradeHistory(params = {}, options = {}) {
1410
+ return this.list("listLargeTradeHistory", { ...options, query: params });
1411
+ }
1412
+ /** @deprecated Use {@link listLargeTrades} (#16304); calls the deprecated `/api/v1/whale-trades`. */
1170
1413
  listWhaleTrades(params = {}, options = {}) {
1171
1414
  return this.list("listWhaleTrades", { ...options, query: params });
1172
1415
  }
1416
+ /** @deprecated Use {@link listLargeTradeHistory} (#16304); calls the deprecated `/api/v1/whale-trades/history`. */
1173
1417
  listWhaleTradeHistory(params = {}, options = {}) {
1174
1418
  return this.list("listWhaleTradeHistory", { ...options, query: params });
1175
1419
  }
@@ -1179,16 +1423,54 @@ export class OxinsiderApiClient {
1179
1423
  listLargePositions(params = {}, options = {}) {
1180
1424
  return this.list("listLargePositions", { ...options, query: params });
1181
1425
  }
1426
+ /**
1427
+ * List ranked sharp-money flows. Canonical since #16308 ("sharp money" is
1428
+ * the pinned product term); it calls `/api/v1/markets/sharp-money-flows`.
1429
+ */
1430
+ listSharpMoneyFlows(params = {}, options = {}) {
1431
+ return this.list("listSharpMoneyFlows", { ...options, query: params });
1432
+ }
1433
+ /**
1434
+ * @deprecated Use {@link listSharpMoneyFlows} (#16308). Kept live; it calls
1435
+ * the deprecated `/api/v1/markets/smart-money-flows`, whose responses carry
1436
+ * `Deprecation` and a `Link rel="successor-version"`.
1437
+ */
1182
1438
  listSmartMoneyFlows(params = {}, options = {}) {
1183
1439
  return this.list("listSmartMoneyFlows", { ...options, query: params });
1184
1440
  }
1185
- /** Canonical alias of {@link listSmartMoneyFlows} (epic #6912). */
1186
- listSharpMoneyFlows(params = {}, options = {}) {
1187
- return this.list("listSharpMoneyFlows", { ...options, query: params });
1441
+ /**
1442
+ * List covered games: both sides with their provider ids and live scores, the
1443
+ * UTC kickoff, the provider's own status, and every linked Polymarket market
1444
+ * with its condition id and outcome token ids. Ordered by kickoff, then by
1445
+ * `event_slug`, with unscheduled games last. An unknown `sport` or `status`
1446
+ * returns an empty page rather than an error, and the response's `coverage`
1447
+ * names what this deployment serves.
1448
+ */
1449
+ listGames(params = {}, options = {}) {
1450
+ return this.list("listGames", { ...options, query: params });
1451
+ }
1452
+ /**
1453
+ * Read one game by its `event_slug`, the identity the `live_sports_updated`
1454
+ * webhook pulse carries. A slug outside the published coverage returns 404.
1455
+ */
1456
+ getGame(eventSlug, options = {}) {
1457
+ return this.call("getGame", { ...options, path: { event_slug: eventSlug } });
1458
+ }
1459
+ /**
1460
+ * List upcoming games ranked by the side profitable wallets hold, with
1461
+ * additive, shadow-only category evidence. `category_skill` never changes
1462
+ * membership, ordering, or sizing. Rows carry `side`, `ranked_at`,
1463
+ * `backing_score` and `side_share`; the older `piled_side`,
1464
+ * `signal_created_at`, `conviction_score` and `smart_score` keys carry the
1465
+ * same values and stay on the wire.
1466
+ */
1467
+ listPreGameSides(params = {}, options = {}) {
1468
+ return this.list("listPreGameSides", { ...options, query: params });
1188
1469
  }
1189
1470
  /**
1190
- * List the funded-primary sports signals with additive, shadow-only category
1191
- * evidence. `category_skill` never changes membership, ordering, or sizing.
1471
+ * @deprecated Use {@link listPreGameSides} (#16310). Kept live; it calls the
1472
+ * deprecated `/api/v1/sports-edge-signals` path, which answers with
1473
+ * `Deprecation` and successor `Link` headers and the same body.
1192
1474
  */
1193
1475
  listSportsEdgeSignals(params = {}, options = {}) {
1194
1476
  return this.list("listSportsEdgeSignals", { ...options, query: params });
@@ -1202,6 +1484,18 @@ export class OxinsiderApiClient {
1202
1484
  * additive wider-holder projection, not an arrival-history or independent
1203
1485
  * denominator view.
1204
1486
  */
1487
+ async listPreGameSideObservations(params, options = {}) {
1488
+ const response = await this.list("listPreGameSideObservations", {
1489
+ ...options,
1490
+ query: params,
1491
+ });
1492
+ return sportsEdgeObservationsResponse(response);
1493
+ }
1494
+ /**
1495
+ * @deprecated Use {@link listPreGameSideObservations} (#16310). Kept live; it
1496
+ * calls the deprecated `/api/v1/sports-edge-observations` path, which answers
1497
+ * with `Deprecation` and successor `Link` headers and the same body.
1498
+ */
1205
1499
  async listSportsEdgeObservations(params, options = {}) {
1206
1500
  const response = await this.list("listSportsEdgeObservations", {
1207
1501
  ...options,
@@ -1218,6 +1512,20 @@ export class OxinsiderApiClient {
1218
1512
  * projection cutoff inside `next_cursor` is excluded while its stable page
1219
1513
  * position remains covered.
1220
1514
  */
1515
+ async listPreGameSideObservationsConditional(params, options = {}) {
1516
+ const response = await this.call("listPreGameSideObservations", {
1517
+ ...options,
1518
+ query: params,
1519
+ });
1520
+ if (isNotModified(response)) {
1521
+ return response;
1522
+ }
1523
+ return sportsEdgeObservationsResponse(response);
1524
+ }
1525
+ /**
1526
+ * @deprecated Use {@link listPreGameSideObservationsConditional} (#16310).
1527
+ * Kept live on the deprecated `/api/v1/sports-edge-observations` path.
1528
+ */
1221
1529
  async listSportsEdgeObservationsConditional(params, options = {}) {
1222
1530
  const response = await this.call("listSportsEdgeObservations", {
1223
1531
  ...options,
@@ -1280,15 +1588,62 @@ export class OxinsiderApiClient {
1280
1588
  query: params,
1281
1589
  });
1282
1590
  }
1591
+ /**
1592
+ * Fetch one suspicious trade by raw `whale_alerts.id` or the `rf_`-prefixed
1593
+ * id list responses emit. The envelope's `object` is `"suspicious_trade"`.
1594
+ */
1595
+ getSuspiciousTrade(id, options = {}) {
1596
+ return this.call("getSuspiciousTrade", { ...options, path: { id } });
1597
+ }
1598
+ /** List stored trades whose recorded suspicion score meets the flag threshold. */
1599
+ listSuspiciousTrades(params = {}, options = {}) {
1600
+ return this.list("listSuspiciousTrades", { ...options, query: params });
1601
+ }
1602
+ /**
1603
+ * @deprecated Use `getSuspiciousTrade()`; renamed in #16301. This method
1604
+ * keeps calling the deprecated `GET /api/v1/insider-radar/{id}`, which stays
1605
+ * live with no retirement date and still answers `object: "radar_flag"`, so
1606
+ * an integration branching on that envelope keeps working.
1607
+ */
1283
1608
  getInsiderRadarFlag(id, options = {}) {
1284
1609
  return this.call("getInsiderRadarFlag", { ...options, path: { id } });
1285
1610
  }
1611
+ /**
1612
+ * @deprecated Use `listSuspiciousTrades()`; renamed in #16301. This method
1613
+ * keeps calling the deprecated `GET /api/v1/insider-radar`, which stays live
1614
+ * with no retirement date and answers with `Deprecation` plus a `Link
1615
+ * rel="successor-version"` header.
1616
+ */
1286
1617
  listInsiderRadar(params = {}, options = {}) {
1287
1618
  return this.list("listInsiderRadar", { ...options, query: params });
1288
1619
  }
1620
+ getLargeTrade(id, options = {}) {
1621
+ return this.call("getLargeTrade", { ...options, path: { id } });
1622
+ }
1623
+ /** @deprecated Use {@link getLargeTrade} (#16304); calls the deprecated `/api/v1/whale-trades/{id}`. */
1289
1624
  getWhaleTrade(id, options = {}) {
1290
1625
  return this.call("getWhaleTrade", { ...options, path: { id } });
1291
1626
  }
1627
+ // --- Exports ---
1628
+ /**
1629
+ * Cancel a submitted export (`POST /api/v1/trader/{address}/export/cancel`, #16254).
1630
+ *
1631
+ * Resolves to the job resource after the cancel, the same shape
1632
+ * `getTraderExportStatus` returns: `cancelled` for a job no worker had
1633
+ * started, `cancel_requested` for a running one (poll the status route at
1634
+ * `poll_after_s` until it reads `cancelled`), or the job unchanged when a
1635
+ * cancel can no longer reach it (its file is being published, or it is
1636
+ * already terminal). Compare `status` rather than assuming success. A
1637
+ * cancel never deletes a ready file, never returns quota, and is safe to
1638
+ * repeat, so it is retried on a transport or 5xx failure like a read.
1639
+ */
1640
+ cancelTraderExport(address, jobId, options = {}) {
1641
+ return this.call("cancelTraderExport", {
1642
+ ...options,
1643
+ path: { address },
1644
+ query: { job_id: jobId },
1645
+ });
1646
+ }
1292
1647
  // --- Webhooks ---
1293
1648
  listWebhooks(options = {}) {
1294
1649
  return this.list("listWebhooks", options);