@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.
- package/README.md +33 -19
- package/dist/catalog.generated.d.ts +46 -10
- package/dist/catalog.generated.d.ts.map +1 -1
- package/dist/catalog.generated.js +55 -10
- package/dist/catalog.generated.js.map +1 -1
- package/dist/cli-lib.d.ts +7 -0
- package/dist/cli-lib.d.ts.map +1 -1
- package/dist/cli-lib.js +83 -17
- package/dist/cli-lib.js.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/product-cli/index.d.ts.map +1 -1
- package/dist/product-cli/index.js +3 -1
- package/dist/product-cli/index.js.map +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +38 -24
- package/dist/prompts/index.js.map +1 -1
- package/dist/sdk/client.d.ts +242 -21
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/client.js +371 -16
- package/dist/sdk/client.js.map +1 -1
- package/dist/sdk/errors.d.ts +21 -1
- package/dist/sdk/errors.d.ts.map +1 -1
- package/dist/sdk/errors.js +46 -1
- package/dist/sdk/errors.js.map +1 -1
- package/dist/sdk/index.d.ts +35 -5
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/pagination.d.ts +7 -7
- package/dist/sdk/pagination.d.ts.map +1 -1
- package/dist/sdk/pagination.js.map +1 -1
- package/dist/sdk/schema.d.ts +1164 -314
- package/dist/sdk/schema.d.ts.map +1 -1
- package/dist/sdk/stream.d.ts +12 -7
- package/dist/sdk/stream.d.ts.map +1 -1
- package/dist/sdk/stream.js +82 -3
- package/dist/sdk/stream.js.map +1 -1
- package/dist/sdk/webhooks.d.ts +148 -12
- package/dist/sdk/webhooks.d.ts.map +1 -1
- package/dist/sdk/webhooks.js +25 -6
- package/dist/sdk/webhooks.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +13 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/games.d.ts +5 -0
- package/dist/tools/games.d.ts.map +1 -0
- package/dist/tools/games.js +103 -0
- package/dist/tools/games.js.map +1 -0
- package/dist/tools/get-insider-radar.d.ts.map +1 -1
- package/dist/tools/get-insider-radar.js +10 -32
- package/dist/tools/get-insider-radar.js.map +1 -1
- package/dist/tools/get-leaderboard.d.ts.map +1 -1
- package/dist/tools/get-leaderboard.js +20 -2
- package/dist/tools/get-leaderboard.js.map +1 -1
- package/dist/tools/get-market-intel.js +2 -2
- package/dist/tools/get-market-intel.js.map +1 -1
- package/dist/tools/get-suspicious-trades.d.ts +26 -0
- package/dist/tools/get-suspicious-trades.d.ts.map +1 -0
- package/dist/tools/get-suspicious-trades.js +91 -0
- package/dist/tools/get-suspicious-trades.js.map +1 -0
- package/dist/tools/get-whale-trades.d.ts +2 -0
- package/dist/tools/get-whale-trades.d.ts.map +1 -1
- package/dist/tools/get-whale-trades.js +18 -6
- package/dist/tools/get-whale-trades.js.map +1 -1
- package/dist/tools/pick-of-the-day.js +1 -1
- package/dist/tools/read-parity.d.ts +9 -1
- package/dist/tools/read-parity.d.ts.map +1 -1
- package/dist/tools/read-parity.js +109 -50
- package/dist/tools/read-parity.js.map +1 -1
- package/package.json +1 -1
package/dist/sdk/client.js
CHANGED
|
@@ -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 {
|
|
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" ||
|
|
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.
|
|
526
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
945
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
1186
|
-
|
|
1187
|
-
|
|
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
|
-
*
|
|
1191
|
-
*
|
|
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);
|