@0xinsider/mcp 2.1.0 → 2.1.3
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 +25 -6
- package/dist/cli-lib.d.ts +1 -0
- package/dist/cli-lib.d.ts.map +1 -1
- package/dist/cli-lib.js +48 -8
- package/dist/cli-lib.js.map +1 -1
- package/dist/client.d.ts +33 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +42 -4
- package/dist/client.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/product-cli/client.d.ts +3 -2
- package/dist/product-cli/client.d.ts.map +1 -1
- package/dist/product-cli/client.js.map +1 -1
- package/dist/sdk/client.d.ts +690 -133
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/client.js +699 -125
- package/dist/sdk/client.js.map +1 -1
- package/dist/sdk/errors.d.ts +42 -4
- package/dist/sdk/errors.d.ts.map +1 -1
- package/dist/sdk/errors.js +103 -2
- package/dist/sdk/errors.js.map +1 -1
- package/dist/sdk/index.d.ts +9 -8
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +6 -4
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/pagination.d.ts +133 -15
- package/dist/sdk/pagination.d.ts.map +1 -1
- package/dist/sdk/pagination.js +132 -34
- package/dist/sdk/pagination.js.map +1 -1
- package/dist/sdk/retry.d.ts +68 -0
- package/dist/sdk/retry.d.ts.map +1 -0
- package/dist/sdk/retry.js +125 -0
- package/dist/sdk/retry.js.map +1 -0
- package/dist/sdk/schema.d.ts +1381 -439
- package/dist/sdk/schema.d.ts.map +1 -1
- package/dist/sdk/stream.d.ts +318 -8
- package/dist/sdk/stream.d.ts.map +1 -1
- package/dist/sdk/stream.js +503 -56
- package/dist/sdk/stream.js.map +1 -1
- package/dist/sdk/webhooks.d.ts +18 -3
- package/dist/sdk/webhooks.d.ts.map +1 -1
- package/dist/sdk/webhooks.js +13 -1
- package/dist/sdk/webhooks.js.map +1 -1
- package/dist/tools/explore-markets.d.ts.map +1 -1
- package/dist/tools/explore-markets.js +2 -5
- package/dist/tools/explore-markets.js.map +1 -1
- package/dist/tools/get-insider-radar.d.ts.map +1 -1
- package/dist/tools/get-insider-radar.js +3 -10
- package/dist/tools/get-insider-radar.js.map +1 -1
- package/dist/tools/get-large-positions.d.ts.map +1 -1
- package/dist/tools/get-large-positions.js +3 -10
- package/dist/tools/get-large-positions.js.map +1 -1
- package/dist/tools/get-leaderboard.d.ts.map +1 -1
- package/dist/tools/get-leaderboard.js +3 -10
- package/dist/tools/get-leaderboard.js.map +1 -1
- package/dist/tools/get-market-intel.d.ts.map +1 -1
- package/dist/tools/get-market-intel.js +3 -6
- package/dist/tools/get-market-intel.js.map +1 -1
- package/dist/tools/get-position-timeline.d.ts.map +1 -1
- package/dist/tools/get-position-timeline.js +3 -10
- package/dist/tools/get-position-timeline.js.map +1 -1
- package/dist/tools/get-positions.d.ts +2 -0
- package/dist/tools/get-positions.d.ts.map +1 -1
- package/dist/tools/get-positions.js +8 -11
- package/dist/tools/get-positions.js.map +1 -1
- package/dist/tools/get-trader-pnl.d.ts.map +1 -1
- package/dist/tools/get-trader-pnl.js +3 -6
- package/dist/tools/get-trader-pnl.js.map +1 -1
- package/dist/tools/get-trader.d.ts.map +1 -1
- package/dist/tools/get-trader.js +3 -6
- package/dist/tools/get-trader.js.map +1 -1
- package/dist/tools/get-trending-wallets.d.ts.map +1 -1
- package/dist/tools/get-trending-wallets.js +3 -10
- package/dist/tools/get-trending-wallets.js.map +1 -1
- package/dist/tools/get-whale-trades.d.ts.map +1 -1
- package/dist/tools/get-whale-trades.js +4 -11
- package/dist/tools/get-whale-trades.js.map +1 -1
- package/dist/tools/pick-of-the-day.d.ts.map +1 -1
- package/dist/tools/pick-of-the-day.js +5 -21
- package/dist/tools/pick-of-the-day.js.map +1 -1
- package/dist/tools/read-parity.d.ts.map +1 -1
- package/dist/tools/read-parity.js +36 -44
- package/dist/tools/read-parity.js.map +1 -1
- package/dist/tools/result.d.ts +31 -0
- package/dist/tools/result.d.ts.map +1 -0
- package/dist/tools/result.js +70 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/tools/search-markets.d.ts.map +1 -1
- package/dist/tools/search-markets.js +16 -11
- package/dist/tools/search-markets.js.map +1 -1
- package/package.json +4 -4
package/dist/sdk/pagination.d.ts
CHANGED
|
@@ -1,26 +1,108 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cursor pagination over the Stripe-style V1 list envelope.
|
|
3
3
|
*
|
|
4
|
-
* Every list endpoint returns `{ object: "list", data, has_more, next_cursor }
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Every list endpoint returns `{ object: "list", data, has_more, next_cursor }`
|
|
5
|
+
* (`backend/src/api_v1/types.rs` `ApiList`: `has_more` is always a boolean,
|
|
6
|
+
* `next_cursor` is a string or omitted). `paginate()` yields each `data[]`
|
|
7
|
+
* item across pages, following `next_cursor` while `has_more` is true.
|
|
8
|
+
* `paginatePages()` yields whole pages when you need the envelope (e.g. to
|
|
9
|
+
* read `meta.cost` or `total`).
|
|
8
10
|
*
|
|
9
|
-
* The
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* The walker is a progress-checked consumer of that protocol (#16246):
|
|
12
|
+
*
|
|
13
|
+
* - A page is validated BEFORE it is yielded. `has_more: true` with no usable
|
|
14
|
+
* `next_cursor` is a `PaginationError` (`missing_cursor`); the backend's own
|
|
15
|
+
* cursor builders refuse to produce that page ("has_more is true for an
|
|
16
|
+
* empty page", `insider_radar.rs`), so a client seeing it is looking at a
|
|
17
|
+
* malformed response, not the end of the collection. Before #16246 the
|
|
18
|
+
* walk returned as if the collection were exhausted.
|
|
19
|
+
* - A `next_cursor` that repeats a cursor this walk already requested is a
|
|
20
|
+
* `PaginationError` (`repeated_cursor`), thrown before the duplicate
|
|
21
|
+
* request. The last `CURSOR_HISTORY_LIMIT` cursors are remembered; a cycle
|
|
22
|
+
* longer than that is not detected, which bounds memory on a long walk.
|
|
23
|
+
* - `maxPages` is validated before any request: a positive integer or
|
|
24
|
+
* `Infinity`; `0`, a negative, fractional or `NaN` value throws `RangeError`.
|
|
25
|
+
* - `has_more: false` ends the walk normally, whatever `next_cursor` says.
|
|
26
|
+
* - A `PaginationError` carries the offending `page`, so its data is not lost,
|
|
27
|
+
* and registers a resume point like any other failure.
|
|
28
|
+
*
|
|
29
|
+
* `options.progress`, when passed, is updated as the walk goes: how many
|
|
30
|
+
* pages were fetched, the last cursor requested, the `next_cursor` of the
|
|
31
|
+
* last page, and why the walk stopped, so a caller that stops at `maxPages`
|
|
32
|
+
* can tell "the collection has more" from "the collection is exhausted" and
|
|
33
|
+
* keep the continuation.
|
|
12
34
|
*/
|
|
13
|
-
import type { ApiListEnvelope, ApiOperationId, ApiRequestOptions, ListParams, OxinsiderApiClient } from "./client.js";
|
|
35
|
+
import type { ApiListEnvelope, ApiOperationId, ApiRequestOptions, ListOperationId, ListParams, OperationEnvelope, OperationItem, OxinsiderApiClient } from "./client.js";
|
|
36
|
+
import type { OperationPath, OperationQuery } from "./schema.js";
|
|
37
|
+
/**
|
|
38
|
+
* How many requested cursors a walk remembers for the repeat check. A cycle
|
|
39
|
+
* longer than this is not detected; the bound keeps a long walk's memory
|
|
40
|
+
* flat instead of growing with every page.
|
|
41
|
+
*/
|
|
42
|
+
export declare const CURSOR_HISTORY_LIMIT = 1024;
|
|
43
|
+
/** Why a walk ended; see `PaginationProgress.stoppedBy`. */
|
|
44
|
+
export type PaginationStop =
|
|
45
|
+
/** The server said `has_more: false`: the collection is exhausted. */
|
|
46
|
+
"exhausted"
|
|
47
|
+
/** The caller's `maxPages` was reached; `nextCursor` continues the walk. */
|
|
48
|
+
| "max_pages";
|
|
49
|
+
/**
|
|
50
|
+
* Live progress of a walk (#16246). Pass an object as `options.progress`
|
|
51
|
+
* and read it after the loop; it is updated before each page is yielded and
|
|
52
|
+
* when the walk ends. On a throw it holds the state at the failed page, the
|
|
53
|
+
* same information `paginationResumePoint(error)` returns.
|
|
54
|
+
*/
|
|
55
|
+
export interface PaginationProgress {
|
|
56
|
+
/** Pages fetched and yielded so far. */
|
|
57
|
+
pagesFetched?: number;
|
|
58
|
+
/** The cursor the most recent page was requested with; `undefined` for the first page. */
|
|
59
|
+
cursor?: string;
|
|
60
|
+
/**
|
|
61
|
+
* The most recent page's `next_cursor`. After `stoppedBy: "max_pages"`
|
|
62
|
+
* this is the continuation: pass it as `query.cursor` to carry on.
|
|
63
|
+
* `null` or `undefined` once the collection is exhausted.
|
|
64
|
+
*/
|
|
65
|
+
nextCursor?: string | null;
|
|
66
|
+
/** Set when the walk ends without throwing. */
|
|
67
|
+
stoppedBy?: PaginationStop;
|
|
68
|
+
}
|
|
14
69
|
export interface PaginateOptions {
|
|
15
70
|
/** Path parameters for templated list paths (e.g. `{ id }` for deliveries). */
|
|
16
71
|
path?: ApiRequestOptions["path"];
|
|
17
72
|
/** Initial query params (filters, `limit`, an initial `cursor`, ...). */
|
|
18
73
|
query?: ListParams;
|
|
74
|
+
/** Reject query names the operation does not publish before the first request. */
|
|
75
|
+
strictQuery?: ApiRequestOptions["strictQuery"];
|
|
19
76
|
/** Forwarded to each request for cooperative cancellation. */
|
|
20
77
|
signal?: AbortSignal;
|
|
21
|
-
/**
|
|
78
|
+
/** Per-request deadline, forwarded to each page; see `ApiRequestOptions.timeoutMs`. */
|
|
79
|
+
timeoutMs?: number | null;
|
|
80
|
+
/** Retries per page, forwarded to each request; see `ApiRequestOptions.maxRetries`. */
|
|
81
|
+
maxRetries?: number;
|
|
82
|
+
/** Extra headers on every page, such as a conditional read's `If-None-Match`. */
|
|
83
|
+
headers?: Record<string, string>;
|
|
84
|
+
/**
|
|
85
|
+
* Hard cap on pages fetched. A positive integer, or `Infinity` / omitted
|
|
86
|
+
* for no cap. Anything else (`0`, negative, fractional, `NaN`) throws a
|
|
87
|
+
* `RangeError` before any request. Reaching it is a caller choice, not
|
|
88
|
+
* exhaustion: `progress.stoppedBy` reads `"max_pages"` and
|
|
89
|
+
* `progress.nextCursor` holds the continuation.
|
|
90
|
+
*/
|
|
22
91
|
maxPages?: number;
|
|
92
|
+
/** Updated as the walk goes; see `PaginationProgress`. */
|
|
93
|
+
progress?: PaginationProgress;
|
|
23
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* `PaginateOptions` bound to one list operation (#16136): `path` required
|
|
97
|
+
* exactly when the route has path parameters, `query` the documented query.
|
|
98
|
+
*/
|
|
99
|
+
export type OperationPaginateOptions<K extends ListOperationId> = Omit<PaginateOptions, "path" | "query"> & (OperationPath[K] extends Record<string, never> ? {
|
|
100
|
+
path?: OperationPath[K];
|
|
101
|
+
} : {
|
|
102
|
+
path: OperationPath[K];
|
|
103
|
+
}) & {
|
|
104
|
+
query?: OperationQuery[K];
|
|
105
|
+
};
|
|
24
106
|
/** Where an interrupted walk can pick up again; see `paginationResumePoint`. */
|
|
25
107
|
export interface PaginationResumePoint {
|
|
26
108
|
/**
|
|
@@ -32,6 +114,34 @@ export interface PaginationResumePoint {
|
|
|
32
114
|
/** Pages already yielded before the failure. */
|
|
33
115
|
pagesFetched: number;
|
|
34
116
|
}
|
|
117
|
+
/** What a page did that the list protocol does not allow. */
|
|
118
|
+
export type PaginationErrorReason =
|
|
119
|
+
/** `has_more: true` with no usable `next_cursor` (missing, `null` or empty). */
|
|
120
|
+
"missing_cursor"
|
|
121
|
+
/** `next_cursor` repeats a cursor this walk already requested: a cycle. */
|
|
122
|
+
| "repeated_cursor";
|
|
123
|
+
/**
|
|
124
|
+
* The server's list response broke the pagination protocol (#16246). The
|
|
125
|
+
* walk stops before yielding the page and before any further request.
|
|
126
|
+
*
|
|
127
|
+
* `page` is the response as received, so its `data` is still available to
|
|
128
|
+
* you; `cursor` is what that page was requested with (`undefined` for the
|
|
129
|
+
* first page) and `nextCursor` is what it offered next. `pagesFetched`
|
|
130
|
+
* counts the pages already yielded. `paginationResumePoint(error)` returns
|
|
131
|
+
* `{ cursor, pagesFetched }` for this error too. Retrying the same page later
|
|
132
|
+
* is reasonable for a transient server fault; a repeat on the same cursor
|
|
133
|
+
* means the route's cursor is broken and is worth reporting with
|
|
134
|
+
* `page.meta.request_id`.
|
|
135
|
+
*/
|
|
136
|
+
export declare class PaginationError<T = unknown> extends Error {
|
|
137
|
+
readonly reason: PaginationErrorReason;
|
|
138
|
+
readonly operationId: ApiOperationId;
|
|
139
|
+
readonly cursor: string | undefined;
|
|
140
|
+
readonly nextCursor: string | null | undefined;
|
|
141
|
+
readonly pagesFetched: number;
|
|
142
|
+
readonly page: ApiListEnvelope<T>;
|
|
143
|
+
constructor(reason: PaginationErrorReason, operationId: ApiOperationId, page: ApiListEnvelope<T>, cursor: string | undefined, pagesFetched: number);
|
|
144
|
+
}
|
|
35
145
|
/**
|
|
36
146
|
* The resume point of an error thrown out of `paginatePages`, `paginate` or
|
|
37
147
|
* `collect`, or `undefined` for any other error (#14281).
|
|
@@ -40,6 +150,7 @@ export interface PaginationResumePoint {
|
|
|
40
150
|
* retries are exhausted the ORIGINAL error is rethrown unchanged, so an
|
|
41
151
|
* `instanceof RateLimitedError` check keeps working, and this function recovers
|
|
42
152
|
* the cursor that the throw would otherwise have destroyed with the generator.
|
|
153
|
+
* A `PaginationError` (#16246) is registered the same way.
|
|
43
154
|
*
|
|
44
155
|
* @example
|
|
45
156
|
* try {
|
|
@@ -54,23 +165,30 @@ export declare function paginationResumePoint(error: unknown): PaginationResumeP
|
|
|
54
165
|
* Async-iterate whole list pages, following `next_cursor` until exhausted.
|
|
55
166
|
* Yields the full envelope so callers can read `meta`/`total`/`has_more`.
|
|
56
167
|
* A failed page throws its original error; `paginationResumePoint(error)`
|
|
57
|
-
* returns the cursor to continue from.
|
|
168
|
+
* returns the cursor to continue from. A page that breaks the protocol
|
|
169
|
+
* throws `PaginationError` before it is yielded (#16246).
|
|
58
170
|
*/
|
|
59
|
-
export declare function paginatePages<
|
|
171
|
+
export declare function paginatePages<K extends ListOperationId>(client: OxinsiderApiClient, operationId: K, options?: OperationPaginateOptions<K>): AsyncGenerator<OperationEnvelope<K>, void, undefined>;
|
|
172
|
+
/** The untyped form: a runtime-chosen operation, or a caller-asserted `T`. */
|
|
173
|
+
export declare function paginatePages<T = unknown>(client: OxinsiderApiClient, operationId: ApiOperationId, options?: PaginateOptions): AsyncGenerator<ApiListEnvelope<T>, void, undefined>;
|
|
60
174
|
/**
|
|
61
175
|
* Async-iterate individual `data[]` items across all pages.
|
|
62
176
|
*
|
|
63
177
|
* @example
|
|
64
|
-
* for await (const trade of paginate
|
|
178
|
+
* for await (const trade of paginate(client, "listWhaleTrades", {
|
|
65
179
|
* query: { min_grade: "S", limit: 100 },
|
|
66
180
|
* })) {
|
|
67
|
-
* handle(trade);
|
|
181
|
+
* handle(trade); // typed as the route's whale trade (#16136)
|
|
68
182
|
* }
|
|
69
183
|
*/
|
|
70
|
-
export declare function paginate<
|
|
184
|
+
export declare function paginate<K extends ListOperationId>(client: OxinsiderApiClient, operationId: K, options?: OperationPaginateOptions<K>): AsyncGenerator<OperationItem<K>, void, undefined>;
|
|
185
|
+
/** The untyped form: a runtime-chosen operation, or a caller-asserted `T`. */
|
|
186
|
+
export declare function paginate<T = unknown>(client: OxinsiderApiClient, operationId: ApiOperationId, options?: PaginateOptions): AsyncGenerator<T, void, undefined>;
|
|
71
187
|
/**
|
|
72
188
|
* Collect every item across all pages into one array. Convenience over
|
|
73
189
|
* `paginate()` for small result sets; prefer the iterator for large ones.
|
|
74
190
|
*/
|
|
75
|
-
export declare function collect<
|
|
191
|
+
export declare function collect<K extends ListOperationId>(client: OxinsiderApiClient, operationId: K, options?: OperationPaginateOptions<K>): Promise<OperationItem<K>[]>;
|
|
192
|
+
/** The untyped form: a runtime-chosen operation, or a caller-asserted `T`. */
|
|
193
|
+
export declare function collect<T = unknown>(client: OxinsiderApiClient, operationId: ApiOperationId, options?: PaginateOptions): Promise<T[]>;
|
|
76
194
|
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../sdk/src/pagination.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../sdk/src/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EACnB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEjE;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,OAAQ,CAAC;AAE1C,4DAA4D;AAC5D,MAAM,MAAM,cAAc;AACxB,sEAAsE;AACpE,WAAW;AACb,4EAA4E;GAC1E,WAAW,CAAC;AAEhB;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0FAA0F;IAC1F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+CAA+C;IAC/C,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,IAAI,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACjC,yEAAyE;IACzE,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,kFAAkF;IAClF,WAAW,CAAC,EAAE,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAC/C,8DAA8D;IAC9D,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,MAAM,wBAAwB,CAAC,CAAC,SAAS,eAAe,IAAI,IAAI,CACpE,eAAe,EACf,MAAM,GAAG,OAAO,CACjB,GACC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAC3C;IAAE,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC;AAElE,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,6DAA6D;AAC7D,MAAM,MAAM,qBAAqB;AAC/B,gFAAgF;AAC9E,gBAAgB;AAClB,2EAA2E;GACzE,iBAAiB,CAAC;AAEtB;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAe,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,KAAK;IACrD,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;IAElC,YACE,MAAM,EAAE,qBAAqB,EAC7B,WAAW,EAAE,cAAc,EAC3B,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,EACxB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,YAAY,EAAE,MAAM,EAerB;CACF;AAID;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,qBAAqB,GAAG,SAAS,CAInC;AAiBD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,eAAe,EACrD,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,CAAC,EACd,OAAO,CAAC,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACpC,cAAc,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;AACzD,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EACvC,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,cAAc,EAC3B,OAAO,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;AAuFvD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,eAAe,EAChD,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,CAAC,EACd,OAAO,CAAC,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACpC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;AACrD,8EAA8E;AAC9E,wBAAgB,QAAQ,CAAC,CAAC,GAAG,OAAO,EAClC,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,cAAc,EAC3B,OAAO,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;AAatC;;;GAGG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,eAAe,EAC/C,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,CAAC,EACd,OAAO,CAAC,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACpC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC/B,8EAA8E;AAC9E,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,EACjC,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,cAAc,EAC3B,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC"}
|
package/dist/sdk/pagination.js
CHANGED
|
@@ -1,15 +1,77 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cursor pagination over the Stripe-style V1 list envelope.
|
|
3
3
|
*
|
|
4
|
-
* Every list endpoint returns `{ object: "list", data, has_more, next_cursor }
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Every list endpoint returns `{ object: "list", data, has_more, next_cursor }`
|
|
5
|
+
* (`backend/src/api_v1/types.rs` `ApiList`: `has_more` is always a boolean,
|
|
6
|
+
* `next_cursor` is a string or omitted). `paginate()` yields each `data[]`
|
|
7
|
+
* item across pages, following `next_cursor` while `has_more` is true.
|
|
8
|
+
* `paginatePages()` yields whole pages when you need the envelope (e.g. to
|
|
9
|
+
* read `meta.cost` or `total`).
|
|
8
10
|
*
|
|
9
|
-
* The
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* The walker is a progress-checked consumer of that protocol (#16246):
|
|
12
|
+
*
|
|
13
|
+
* - A page is validated BEFORE it is yielded. `has_more: true` with no usable
|
|
14
|
+
* `next_cursor` is a `PaginationError` (`missing_cursor`); the backend's own
|
|
15
|
+
* cursor builders refuse to produce that page ("has_more is true for an
|
|
16
|
+
* empty page", `insider_radar.rs`), so a client seeing it is looking at a
|
|
17
|
+
* malformed response, not the end of the collection. Before #16246 the
|
|
18
|
+
* walk returned as if the collection were exhausted.
|
|
19
|
+
* - A `next_cursor` that repeats a cursor this walk already requested is a
|
|
20
|
+
* `PaginationError` (`repeated_cursor`), thrown before the duplicate
|
|
21
|
+
* request. The last `CURSOR_HISTORY_LIMIT` cursors are remembered; a cycle
|
|
22
|
+
* longer than that is not detected, which bounds memory on a long walk.
|
|
23
|
+
* - `maxPages` is validated before any request: a positive integer or
|
|
24
|
+
* `Infinity`; `0`, a negative, fractional or `NaN` value throws `RangeError`.
|
|
25
|
+
* - `has_more: false` ends the walk normally, whatever `next_cursor` says.
|
|
26
|
+
* - A `PaginationError` carries the offending `page`, so its data is not lost,
|
|
27
|
+
* and registers a resume point like any other failure.
|
|
28
|
+
*
|
|
29
|
+
* `options.progress`, when passed, is updated as the walk goes: how many
|
|
30
|
+
* pages were fetched, the last cursor requested, the `next_cursor` of the
|
|
31
|
+
* last page, and why the walk stopped, so a caller that stops at `maxPages`
|
|
32
|
+
* can tell "the collection has more" from "the collection is exhausted" and
|
|
33
|
+
* keep the continuation.
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* How many requested cursors a walk remembers for the repeat check. A cycle
|
|
37
|
+
* longer than this is not detected; the bound keeps a long walk's memory
|
|
38
|
+
* flat instead of growing with every page.
|
|
12
39
|
*/
|
|
40
|
+
export const CURSOR_HISTORY_LIMIT = 1_024;
|
|
41
|
+
/**
|
|
42
|
+
* The server's list response broke the pagination protocol (#16246). The
|
|
43
|
+
* walk stops before yielding the page and before any further request.
|
|
44
|
+
*
|
|
45
|
+
* `page` is the response as received, so its `data` is still available to
|
|
46
|
+
* you; `cursor` is what that page was requested with (`undefined` for the
|
|
47
|
+
* first page) and `nextCursor` is what it offered next. `pagesFetched`
|
|
48
|
+
* counts the pages already yielded. `paginationResumePoint(error)` returns
|
|
49
|
+
* `{ cursor, pagesFetched }` for this error too. Retrying the same page later
|
|
50
|
+
* is reasonable for a transient server fault; a repeat on the same cursor
|
|
51
|
+
* means the route's cursor is broken and is worth reporting with
|
|
52
|
+
* `page.meta.request_id`.
|
|
53
|
+
*/
|
|
54
|
+
export class PaginationError extends Error {
|
|
55
|
+
reason;
|
|
56
|
+
operationId;
|
|
57
|
+
cursor;
|
|
58
|
+
nextCursor;
|
|
59
|
+
pagesFetched;
|
|
60
|
+
page;
|
|
61
|
+
constructor(reason, operationId, page, cursor, pagesFetched) {
|
|
62
|
+
const requestId = page.meta?.request_id;
|
|
63
|
+
super(reason === "missing_cursor"
|
|
64
|
+
? `0xinsider API ${operationId} page ${String(pagesFetched + 1)} says has_more but carries no next_cursor${requestId ? ` (request ${requestId})` : ""}; the walk cannot continue safely`
|
|
65
|
+
: `0xinsider API ${operationId} page ${String(pagesFetched + 1)} offers next_cursor ${JSON.stringify(page.next_cursor)}, which this walk already requested${requestId ? ` (request ${requestId})` : ""}; stopping before the duplicate request`);
|
|
66
|
+
this.name = "PaginationError";
|
|
67
|
+
this.reason = reason;
|
|
68
|
+
this.operationId = operationId;
|
|
69
|
+
this.cursor = cursor;
|
|
70
|
+
this.nextCursor = page.next_cursor;
|
|
71
|
+
this.pagesFetched = pagesFetched;
|
|
72
|
+
this.page = page;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
13
75
|
const resumePoints = new WeakMap();
|
|
14
76
|
/**
|
|
15
77
|
* The resume point of an error thrown out of `paginatePages`, `paginate` or
|
|
@@ -19,6 +81,7 @@ const resumePoints = new WeakMap();
|
|
|
19
81
|
* retries are exhausted the ORIGINAL error is rethrown unchanged, so an
|
|
20
82
|
* `instanceof RateLimitedError` check keeps working, and this function recovers
|
|
21
83
|
* the cursor that the throw would otherwise have destroyed with the generator.
|
|
84
|
+
* A `PaginationError` (#16246) is registered the same way.
|
|
22
85
|
*
|
|
23
86
|
* @example
|
|
24
87
|
* try {
|
|
@@ -33,58 +96,97 @@ export function paginationResumePoint(error) {
|
|
|
33
96
|
? resumePoints.get(error)
|
|
34
97
|
: undefined;
|
|
35
98
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
99
|
+
function assertMaxPages(value) {
|
|
100
|
+
if (value === undefined || value === Infinity)
|
|
101
|
+
return Infinity;
|
|
102
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
103
|
+
throw new RangeError(`maxPages must be a positive integer or Infinity, got ${String(value)}`);
|
|
104
|
+
}
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
/** A `next_cursor` the walk can request: a non-empty string. */
|
|
108
|
+
function usableCursor(value) {
|
|
109
|
+
return typeof value === "string" && value !== "";
|
|
110
|
+
}
|
|
42
111
|
export async function* paginatePages(client, operationId, options = {}) {
|
|
43
|
-
const { path, query, signal,
|
|
112
|
+
const { path, query, strictQuery, signal, progress, timeoutMs, maxRetries, headers } = options;
|
|
113
|
+
const maxPages = assertMaxPages(options.maxPages);
|
|
44
114
|
let cursor = query?.cursor;
|
|
45
115
|
let pages = 0;
|
|
116
|
+
// Every cursor requested so far, newest last, capped at CURSOR_HISTORY_LIMIT.
|
|
117
|
+
const requested = new Set();
|
|
118
|
+
const requestedOrder = [];
|
|
119
|
+
const remember = (value) => {
|
|
120
|
+
if (requested.has(value))
|
|
121
|
+
return;
|
|
122
|
+
requested.add(value);
|
|
123
|
+
requestedOrder.push(value);
|
|
124
|
+
if (requestedOrder.length > CURSOR_HISTORY_LIMIT) {
|
|
125
|
+
const oldest = requestedOrder.shift();
|
|
126
|
+
if (oldest !== undefined)
|
|
127
|
+
requested.delete(oldest);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const record = (fields) => {
|
|
131
|
+
if (progress)
|
|
132
|
+
Object.assign(progress, fields);
|
|
133
|
+
};
|
|
134
|
+
const fail = (error) => {
|
|
135
|
+
if (!resumePoints.has(error)) {
|
|
136
|
+
resumePoints.set(error, { cursor, pagesFetched: pages });
|
|
137
|
+
}
|
|
138
|
+
return error;
|
|
139
|
+
};
|
|
46
140
|
for (;;) {
|
|
47
141
|
if (signal?.aborted) {
|
|
48
142
|
throw signal.reason instanceof Error
|
|
49
143
|
? signal.reason
|
|
50
144
|
: new DOMException("The pagination was aborted", "AbortError");
|
|
51
145
|
}
|
|
146
|
+
if (cursor !== undefined)
|
|
147
|
+
remember(cursor);
|
|
52
148
|
let page;
|
|
53
149
|
try {
|
|
54
150
|
page = await client.list(operationId, {
|
|
55
151
|
path,
|
|
56
152
|
query: { ...query, ...(cursor === undefined ? {} : { cursor }) },
|
|
153
|
+
strictQuery,
|
|
57
154
|
signal,
|
|
155
|
+
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
156
|
+
...(maxRetries === undefined ? {} : { maxRetries }),
|
|
157
|
+
...(headers === undefined ? {} : { headers }),
|
|
58
158
|
});
|
|
59
159
|
}
|
|
60
160
|
catch (error) {
|
|
61
|
-
if (typeof error === "object" && error !== null
|
|
62
|
-
|
|
63
|
-
}
|
|
161
|
+
if (typeof error === "object" && error !== null)
|
|
162
|
+
fail(error);
|
|
64
163
|
throw error;
|
|
65
164
|
}
|
|
165
|
+
record({ pagesFetched: pages, cursor, nextCursor: page.next_cursor });
|
|
166
|
+
const next = page.next_cursor;
|
|
167
|
+
if (page.has_more) {
|
|
168
|
+
if (!usableCursor(next)) {
|
|
169
|
+
throw fail(new PaginationError("missing_cursor", operationId, page, cursor, pages));
|
|
170
|
+
}
|
|
171
|
+
if (requested.has(next)) {
|
|
172
|
+
throw fail(new PaginationError("repeated_cursor", operationId, page, cursor, pages));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
66
175
|
yield page;
|
|
67
176
|
pages += 1;
|
|
68
|
-
|
|
69
|
-
if (!page.has_more
|
|
177
|
+
record({ pagesFetched: pages, cursor, nextCursor: next });
|
|
178
|
+
if (!page.has_more) {
|
|
179
|
+
record({ pagesFetched: pages, cursor, nextCursor: next, stoppedBy: "exhausted" });
|
|
70
180
|
return;
|
|
71
181
|
}
|
|
72
|
-
if (
|
|
182
|
+
if (pages >= maxPages) {
|
|
183
|
+
record({ pagesFetched: pages, cursor, nextCursor: next, stoppedBy: "max_pages" });
|
|
73
184
|
return;
|
|
74
185
|
}
|
|
186
|
+
// `has_more` was true and `next` passed both checks above.
|
|
75
187
|
cursor = next;
|
|
76
188
|
}
|
|
77
189
|
}
|
|
78
|
-
/**
|
|
79
|
-
* Async-iterate individual `data[]` items across all pages.
|
|
80
|
-
*
|
|
81
|
-
* @example
|
|
82
|
-
* for await (const trade of paginate<WhaleTrade>(client, "listWhaleTrades", {
|
|
83
|
-
* query: { min_grade: "S", limit: 100 },
|
|
84
|
-
* })) {
|
|
85
|
-
* handle(trade);
|
|
86
|
-
* }
|
|
87
|
-
*/
|
|
88
190
|
export async function* paginate(client, operationId, options = {}) {
|
|
89
191
|
for await (const page of paginatePages(client, operationId, options)) {
|
|
90
192
|
for (const item of page.data) {
|
|
@@ -92,10 +194,6 @@ export async function* paginate(client, operationId, options = {}) {
|
|
|
92
194
|
}
|
|
93
195
|
}
|
|
94
196
|
}
|
|
95
|
-
/**
|
|
96
|
-
* Collect every item across all pages into one array. Convenience over
|
|
97
|
-
* `paginate()` for small result sets; prefer the iterator for large ones.
|
|
98
|
-
*/
|
|
99
197
|
export async function collect(client, operationId, options = {}) {
|
|
100
198
|
const items = [];
|
|
101
199
|
for await (const item of paginate(client, operationId, options)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../../sdk/src/pagination.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../../sdk/src/pagination.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Retry-After` parsing and the waits it drives, shared by the REST retry
|
|
3
|
+
* loop (`client.ts`) and the SSE reconnect loop (`stream.ts`) so the two
|
|
4
|
+
* cannot read the same header differently (#16249).
|
|
5
|
+
*
|
|
6
|
+
* Two facts shape this module:
|
|
7
|
+
*
|
|
8
|
+
* 1. `Retry-After` is either delta-seconds or an HTTP-date (RFC 9110 §10.2.3,
|
|
9
|
+
* https://www.rfc-editor.org/rfc/rfc9110.html#name-retry-after). Both
|
|
10
|
+
* loops parsed only the number and treated a date as "no header".
|
|
11
|
+
* 2. Node schedules a `setTimeout` delay above 2147483647 ms (about 24.8 days)
|
|
12
|
+
* as 1 ms, with a warning
|
|
13
|
+
* (https://nodejs.org/api/timers.html#settimeoutcallback-delay-args). The
|
|
14
|
+
* stream loop multiplied any `Retry-After` by 1000 and handed it straight
|
|
15
|
+
* to the timer, so a long server-requested wait -- `monthly_quota_exceeded`
|
|
16
|
+
* names the first of next month -- would have reconnected at once, the
|
|
17
|
+
* opposite of what the server asked.
|
|
18
|
+
*
|
|
19
|
+
* The policy is therefore: parse both forms into a non-negative number of
|
|
20
|
+
* seconds; never wait in-process past a ceiling the caller can see (60 s by
|
|
21
|
+
* default, the same for REST and SSE); when the server asks for longer, hand
|
|
22
|
+
* the caller a typed error carrying the not-before instant and the resume
|
|
23
|
+
* context, never a clamped earlier retry; and when a caller opts into waiting
|
|
24
|
+
* longer, wait in timer-sized chunks so the timer range is never exceeded.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* The largest delay one `setTimeout` can hold in Node (2^31 - 1 ms). A larger
|
|
28
|
+
* value is scheduled as 1 ms, so every wait here is cut into chunks of at
|
|
29
|
+
* most this size.
|
|
30
|
+
*/
|
|
31
|
+
export declare const MAX_TIMER_DELAY_MS = 2147483647;
|
|
32
|
+
/**
|
|
33
|
+
* The longest server-requested wait either loop holds in-process by default.
|
|
34
|
+
* A `Retry-After` beyond it is the caller's to schedule: the REST loop throws
|
|
35
|
+
* the response's error (`retryAfterSeconds`, `retryAt`), the stream loop
|
|
36
|
+
* throws `StreamRetryDeferredError`.
|
|
37
|
+
*/
|
|
38
|
+
export declare const RETRY_AFTER_CEILING_MS = 60000;
|
|
39
|
+
/**
|
|
40
|
+
* Parse a `Retry-After` header value into seconds to wait, or `null` when
|
|
41
|
+
* there is no usable value.
|
|
42
|
+
*
|
|
43
|
+
* - Delta-seconds: a finite, non-negative number (`"60"`, `"1.5"`). A negative
|
|
44
|
+
* or non-finite number (`"-1"`, `"Infinity"`, `"NaN"`) is `null`: the
|
|
45
|
+
* grammar does not allow it, and guessing a wait from it would be inventing
|
|
46
|
+
* a server instruction.
|
|
47
|
+
* - HTTP-date (`"Wed, 01 Oct 2026 00:00:00 GMT"`): the seconds from `nowMs`
|
|
48
|
+
* to that instant. A date already past is `0` (the server said "after an
|
|
49
|
+
* instant that has passed", which is "now"), never negative.
|
|
50
|
+
* - Anything else (`""`, `"soon"`) is `null`.
|
|
51
|
+
*
|
|
52
|
+
* `null` means "as if the header were absent": the caller falls back to its
|
|
53
|
+
* own backoff. It never means "retry at once".
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseRetryAfter(header: string | null | undefined, nowMs?: number): number | null;
|
|
56
|
+
/** `parseRetryAfter` over a response's `Retry-After` header. */
|
|
57
|
+
export declare function retryAfterSeconds(response: Response): number | null;
|
|
58
|
+
/**
|
|
59
|
+
* Resolve after `ms`, or reject with the signal's reason the moment it
|
|
60
|
+
* aborts. A wait longer than `MAX_TIMER_DELAY_MS` runs as consecutive timers
|
|
61
|
+
* of at most that size, so it is never handed to `setTimeout` as one value
|
|
62
|
+
* that Node would schedule as 1 ms. `ms` must be a non-negative number;
|
|
63
|
+
* `Infinity` is refused because it can never elapse.
|
|
64
|
+
*/
|
|
65
|
+
export declare function sleepUnlessAborted(ms: number, signal: AbortSignal | undefined): Promise<void>;
|
|
66
|
+
/** Resolve `true` after `ms`, or `false` the moment `signal` aborts. */
|
|
67
|
+
export declare function waitUnlessAborted(ms: number, signal: AbortSignal | undefined): Promise<boolean>;
|
|
68
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../sdk/src/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,aAAgB,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAE7C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,KAAK,GAAE,MAAmB,GACzB,MAAM,GAAG,IAAI,CAaf;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAEnE;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,wEAAwE;AACxE,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,OAAO,CAAC,CAQlB"}
|