@0xinsider/mcp 2.0.1 → 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 +27 -7
- package/dist/catalog.generated.d.ts +4 -0
- package/dist/catalog.generated.d.ts.map +1 -1
- package/dist/catalog.generated.js +5 -0
- package/dist/catalog.generated.js.map +1 -1
- 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 +36 -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 +705 -131
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/client.js +719 -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 +1536 -430
- 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/server.d.ts.map +1 -1
- package/dist/server.js +2 -1
- package/dist/server.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 +1 -0
- package/dist/tools/read-parity.d.ts.map +1 -1
- package/dist/tools/read-parity.js +69 -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/stream.d.ts
CHANGED
|
@@ -21,8 +21,27 @@
|
|
|
21
21
|
*
|
|
22
22
|
* Filters (per-connection, subscribe-time): `event` (comma-separated frame
|
|
23
23
|
* types), `condition_id`, and `min_grade` (S|A|B|C|D|F).
|
|
24
|
+
*
|
|
25
|
+
* Protocol validity (#16248). The decoder is bounded and fails visibly:
|
|
26
|
+
* - A successful response whose media type is not `text/event-stream` is
|
|
27
|
+
* `StreamProtocolError` (`unexpected_media_type`), not an empty stream.
|
|
28
|
+
* - A data frame whose payload is not JSON, not an object, or has no usable
|
|
29
|
+
* sequence (a finite `seq` in the envelope, or a finite SSE `id`) is a
|
|
30
|
+
* `StreamProtocolError` (`invalid_json`, `invalid_envelope`,
|
|
31
|
+
* `unusable_sequence`); a resync frame whose payload is not an object is
|
|
32
|
+
* `invalid_resync`. Before #16248 such frames were skipped or yielded with
|
|
33
|
+
* `NaN`, and the next valid frame moved the cursor past the gap.
|
|
34
|
+
* - A frame that has not reached its blank-line delimiter after
|
|
35
|
+
* `maxFrameBytes` (default 1 MiB) is `frame_too_large`; the reader is
|
|
36
|
+
* released and the connection closed.
|
|
37
|
+
* - The error carries `lastSeq`, the last sequence delivered before it, so a
|
|
38
|
+
* malformed frame never moves the cursor and a caller can decide whether
|
|
39
|
+
* to resume from there (which replays the frame while it is retained),
|
|
40
|
+
* skip past `frameId`, or refetch state. No raw payload is on the error.
|
|
41
|
+
* Comment lines (`: keep-alive`), LF and CRLF framing, unknown SSE fields
|
|
42
|
+
* and unknown-but-valid envelope `type`s are compatible as before.
|
|
24
43
|
*/
|
|
25
|
-
import type
|
|
44
|
+
import { type Grade, type OxinsiderApiClient } from "./client.js";
|
|
26
45
|
/** A live feed envelope frame: `{ seq, published_at, type, ...payload }`. */
|
|
27
46
|
export interface FeedEnvelope {
|
|
28
47
|
/** Cluster-shared monotonic sequence id; also the SSE event id. */
|
|
@@ -68,14 +87,78 @@ export interface StreamOptions extends StreamFilters {
|
|
|
68
87
|
/** Invoked once for the resync marker frame, if one is emitted. */
|
|
69
88
|
onResync?: (marker: ResyncMarker) => void;
|
|
70
89
|
/**
|
|
71
|
-
* Optional cursor object whose `seq` is updated to the last
|
|
90
|
+
* Optional cursor object whose `seq` is updated to the last DELIVERED
|
|
72
91
|
* envelope `seq` as frames arrive. Pass the same object back as
|
|
73
92
|
* `lastEventId: cursor.seq` on reconnect to resume from where you left off.
|
|
93
|
+
*
|
|
94
|
+
* Received, not processed (#16247). It is written before the frame reaches
|
|
95
|
+
* your code, so it says the frame arrived and nothing about whether your
|
|
96
|
+
* handling of it succeeded: resuming from it after a handler failure skips
|
|
97
|
+
* that event. When losing an event would lose work, drive the stream with
|
|
98
|
+
* `consumeStreamCheckpointed`, whose `StreamCheckpoint` advances only after
|
|
99
|
+
* the handler and your durable write resolve, and keep this cursor for
|
|
100
|
+
* transport progress.
|
|
74
101
|
*/
|
|
75
102
|
cursor?: {
|
|
76
103
|
seq?: number;
|
|
77
104
|
};
|
|
105
|
+
/**
|
|
106
|
+
* Byte ceiling for one undelivered frame (#16248). Default
|
|
107
|
+
* `DEFAULT_MAX_STREAM_FRAME_BYTES` (1 MiB). A connection that sends more
|
|
108
|
+
* than this without a blank-line delimiter ends with
|
|
109
|
+
* `StreamProtocolError` (`frame_too_large`) and the reader is released.
|
|
110
|
+
* A positive finite integer; the largest real frame is a few KB.
|
|
111
|
+
*/
|
|
112
|
+
maxFrameBytes?: number;
|
|
113
|
+
}
|
|
114
|
+
/** Default for `StreamOptions.maxFrameBytes`: 1 MiB. */
|
|
115
|
+
export declare const DEFAULT_MAX_STREAM_FRAME_BYTES = 1048576;
|
|
116
|
+
/** What the stream did that the SSE contract does not allow. */
|
|
117
|
+
export type StreamProtocolErrorReason =
|
|
118
|
+
/** A 2xx whose `Content-Type` is not `text/event-stream`. */
|
|
119
|
+
"unexpected_media_type"
|
|
120
|
+
/** A data frame whose payload is not JSON. */
|
|
121
|
+
| "invalid_json"
|
|
122
|
+
/** A data frame whose payload is JSON but not an object (or is `null`, an array). */
|
|
123
|
+
| "invalid_envelope"
|
|
124
|
+
/** A data frame with no finite `seq` in the envelope and no finite SSE `id`. */
|
|
125
|
+
| "unusable_sequence"
|
|
126
|
+
/** A resync frame whose payload is not an object, or whose `type` is not `resync`. */
|
|
127
|
+
| "invalid_resync"
|
|
128
|
+
/** A frame grew past `maxFrameBytes` without reaching its delimiter. */
|
|
129
|
+
| "frame_too_large";
|
|
130
|
+
/**
|
|
131
|
+
* The stream broke the SSE contract (#16248). The connection is closed and
|
|
132
|
+
* the reader released before this is thrown. `lastSeq` is the last sequence
|
|
133
|
+
* delivered on this connection, or `undefined` when none was: no malformed
|
|
134
|
+
* frame moves the cursor. `frameId` is the SSE `id` of the offending frame
|
|
135
|
+
* when it carried one, `event` its SSE event name, `bytes` its size, and
|
|
136
|
+
* `mediaType` the response's `Content-Type` for `unexpected_media_type`. The
|
|
137
|
+
* raw payload is deliberately not carried: it may hold data you would not
|
|
138
|
+
* want in a log, and `frameId` plus `lastSeq` name the frame exactly.
|
|
139
|
+
*
|
|
140
|
+
* `streamFeedResilient` treats this as permanent: reconnecting from
|
|
141
|
+
* `lastSeq` would replay the same frame while the server retains it. Decide:
|
|
142
|
+
* resume from `lastSeq` later, resume after `frameId` to skip it, or refetch
|
|
143
|
+
* state and attach live.
|
|
144
|
+
*/
|
|
145
|
+
export declare class StreamProtocolError extends Error {
|
|
146
|
+
readonly reason: StreamProtocolErrorReason;
|
|
147
|
+
readonly lastSeq: number | undefined;
|
|
148
|
+
readonly frameId: number | undefined;
|
|
149
|
+
readonly event: string | undefined;
|
|
150
|
+
readonly bytes: number | undefined;
|
|
151
|
+
readonly mediaType: string | undefined;
|
|
152
|
+
constructor(reason: StreamProtocolErrorReason, detail: {
|
|
153
|
+
lastSeq: number | undefined;
|
|
154
|
+
frameId?: number;
|
|
155
|
+
event?: string;
|
|
156
|
+
bytes?: number;
|
|
157
|
+
mediaType?: string | null;
|
|
158
|
+
});
|
|
78
159
|
}
|
|
160
|
+
/** `Content-Type` names an event stream: `text/event-stream`, with or without parameters. */
|
|
161
|
+
export declare function isEventStreamMediaType(contentType: string | null): boolean;
|
|
79
162
|
/** One yielded item from the stream iterator. */
|
|
80
163
|
export type StreamEvent = {
|
|
81
164
|
kind: "event";
|
|
@@ -114,9 +197,23 @@ export interface ResilientStreamOptions extends StreamOptions {
|
|
|
114
197
|
* the previous connection ended (`undefined` for a clean server close).
|
|
115
198
|
*/
|
|
116
199
|
onReconnect?: (attempt: number, lastSeq: number | undefined, cause: unknown) => void;
|
|
200
|
+
/**
|
|
201
|
+
* The longest server-requested wait (`Retry-After`) the loop holds
|
|
202
|
+
* in-process, in ms. Default `DEFAULT_MAX_STREAM_RETRY_AFTER_MS` (60 000,
|
|
203
|
+
* the REST client's ceiling). A refusal asking for longer ends the loop
|
|
204
|
+
* with `StreamRetryDeferredError`, which carries the not-before instant
|
|
205
|
+
* (`retryAt`) and the seq to resume after (`lastSeq`), so the wait is
|
|
206
|
+
* yours to schedule and no reconnect is spent on it. `Infinity` opts into
|
|
207
|
+
* waiting however long the server says, in timer-sized chunks; it can hold
|
|
208
|
+
* the process for days on a `monthly_quota_exceeded` refusal, which is why
|
|
209
|
+
* it is not the default (#16249).
|
|
210
|
+
*/
|
|
211
|
+
maxRetryAfterMs?: number;
|
|
117
212
|
}
|
|
118
213
|
/** Default for `ResilientStreamOptions.maxReconnects`. */
|
|
119
214
|
export declare const DEFAULT_MAX_STREAM_RECONNECTS = 10;
|
|
215
|
+
/** Default for `ResilientStreamOptions.maxRetryAfterMs`. */
|
|
216
|
+
export declare const DEFAULT_MAX_STREAM_RETRY_AFTER_MS = 60000;
|
|
120
217
|
/**
|
|
121
218
|
* `streamFeedResilient` gave up after `maxReconnects` consecutive failed
|
|
122
219
|
* connections. `lastSeq` is the seq to resume after (pass it as `lastEventId`
|
|
@@ -127,16 +224,42 @@ export declare class StreamReconnectsExhaustedError extends Error {
|
|
|
127
224
|
readonly attempts: number;
|
|
128
225
|
constructor(attempts: number, lastSeq: number | undefined, cause: unknown);
|
|
129
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* `streamFeedResilient` was refused with a `Retry-After` longer than
|
|
229
|
+
* `maxRetryAfterMs`, so the wait is yours to schedule (#16249). `retryAt` is
|
|
230
|
+
* the server's not-before instant as this client read it (the header's
|
|
231
|
+
* seconds added to the local clock, or the header's HTTP-date); `cause` is
|
|
232
|
+
* the refusal, whose `retryAt` (from the body's `retry_at`) is the server's
|
|
233
|
+
* own clock reading of the same instant. `lastSeq` is the seq to resume after:
|
|
234
|
+
* pass it as `lastEventId` when you reconnect at `retryAt`. `attempts` is how
|
|
235
|
+
* many consecutive failed connections preceded this one; the refusal itself
|
|
236
|
+
* spent none of `maxReconnects`.
|
|
237
|
+
*
|
|
238
|
+
* Nothing here was clamped: a wait the timer cannot hold is never shortened
|
|
239
|
+
* into an earlier reconnect.
|
|
240
|
+
*/
|
|
241
|
+
export declare class StreamRetryDeferredError extends Error {
|
|
242
|
+
readonly retryAt: Date;
|
|
243
|
+
readonly retryAfterMs: number;
|
|
244
|
+
readonly lastSeq: number | undefined;
|
|
245
|
+
readonly attempts: number;
|
|
246
|
+
constructor(retryAfterMs: number, lastSeq: number | undefined, attempts: number, cause: unknown);
|
|
247
|
+
}
|
|
130
248
|
/**
|
|
131
249
|
* `streamFeed` with the reconnect-and-resume loop built in (#14286).
|
|
132
250
|
*
|
|
133
251
|
* - A clean server close, a network error, a 429 or a 5xx reconnects,
|
|
134
252
|
* resuming after the last delivered seq (`Last-Event-ID`). Before any frame
|
|
135
253
|
* arrives it resumes from `lastEventId`, or attaches live when that is unset.
|
|
136
|
-
* - The wait is `Retry-After`
|
|
137
|
-
* otherwise a jittered backoff from 1 s capped at
|
|
254
|
+
* - The wait is `Retry-After` (delta-seconds or an HTTP-date) plus jitter when
|
|
255
|
+
* the refusal carries one, otherwise a jittered backoff from 1 s capped at
|
|
256
|
+
* 30 s. A `Retry-After` past `maxRetryAfterMs` (60 s by default) is not
|
|
257
|
+
* waited out: the loop throws `StreamRetryDeferredError` with `retryAt` and
|
|
258
|
+
* `lastSeq`, spending no reconnect, and never clamps the wait to an earlier
|
|
259
|
+
* one (#16249).
|
|
138
260
|
* - Any other 4xx (400, 401, 402, 403, 423) is thrown at once: it cannot heal
|
|
139
|
-
* on its own.
|
|
261
|
+
* on its own. So is `StreamProtocolError` (#16248): a resume from
|
|
262
|
+
* `lastSeq` would replay the malformed frame, so the decision is yours.
|
|
140
263
|
* - After `maxReconnects` consecutive connections that delivered nothing, it
|
|
141
264
|
* throws `StreamReconnectsExhaustedError` carrying `lastSeq`.
|
|
142
265
|
* - `resync` markers are yielded unchanged, and `onResync` still fires. The
|
|
@@ -148,7 +271,10 @@ export declare class StreamReconnectsExhaustedError extends Error {
|
|
|
148
271
|
* - No request deadline applies, as with `streamFeed`.
|
|
149
272
|
*
|
|
150
273
|
* `options.cursor`, when passed, tracks the last delivered seq across every
|
|
151
|
-
* connection.
|
|
274
|
+
* connection -- delivered, not processed (#16247). This loop resumes from it,
|
|
275
|
+
* so a consumer whose handler can fail should drive the stream with
|
|
276
|
+
* `consumeStreamCheckpointed` instead, which resumes from an acknowledged
|
|
277
|
+
* checkpoint and replays the event it failed on.
|
|
152
278
|
*
|
|
153
279
|
* @example
|
|
154
280
|
* const controller = new AbortController();
|
|
@@ -166,17 +292,201 @@ export declare function streamFeedResilient(client: OxinsiderApiClient, options?
|
|
|
166
292
|
* Callback-style stream consumer for environments where an async iterator is
|
|
167
293
|
* awkward. Returns a promise that resolves when the stream ends (or rejects on
|
|
168
294
|
* error / abort). Pass a `signal` to stop it.
|
|
295
|
+
*
|
|
296
|
+
* Delivery, not processing (#16247): `options.cursor` is written by
|
|
297
|
+
* `streamFeed` BEFORE the frame is yielded, so it has already moved past an
|
|
298
|
+
* event whose `onEvent` then throws. Reconnecting from it skips that event.
|
|
299
|
+
* For a consumer that must not lose work, use `consumeStreamCheckpointed`,
|
|
300
|
+
* which advances an acknowledged checkpoint only after the handler and your
|
|
301
|
+
* own durable write have both resolved.
|
|
169
302
|
*/
|
|
170
303
|
export declare function consumeStream(client: OxinsiderApiClient, handlers: {
|
|
171
304
|
onEvent?: (envelope: FeedEnvelope, seq: number) => void | Promise<void>;
|
|
172
305
|
onResync?: (marker: ResyncMarker, seq: number | null) => void | Promise<void>;
|
|
173
306
|
}, options?: StreamOptions): Promise<void>;
|
|
174
|
-
|
|
307
|
+
/**
|
|
308
|
+
* An acknowledged processing checkpoint (#16247): the last `seq` whose
|
|
309
|
+
* handling COMPLETED, which is not the same thing as the last `seq` that
|
|
310
|
+
* arrived. `StreamOptions.cursor` is the received cursor -- transport
|
|
311
|
+
* progress, written before the frame is handed to you. This is the processed
|
|
312
|
+
* one, written after your handler and your own durable write have resolved.
|
|
313
|
+
*
|
|
314
|
+
* Own the object if you persist the checkpoint yourself: pass it in, read
|
|
315
|
+
* `seq` after the consumer returns or throws, and pass the stored value back
|
|
316
|
+
* as `lastEventId` when you resume in a later process.
|
|
317
|
+
*/
|
|
318
|
+
export interface StreamCheckpoint {
|
|
319
|
+
/** The last acknowledged sequence, or `undefined` until one is acknowledged. */
|
|
320
|
+
seq?: number;
|
|
321
|
+
}
|
|
322
|
+
/** What the checkpoint advanced past: a feed envelope, or a resync refresh. */
|
|
323
|
+
export type StreamCheckpointReason = "event" | "resync";
|
|
324
|
+
/**
|
|
325
|
+
* Which awaited step rejected: your event handler, your resync refresh, or
|
|
326
|
+
* your `onCheckpoint` durable write.
|
|
327
|
+
*/
|
|
328
|
+
export type StreamHandlerStage = "event" | "resync" | "checkpoint";
|
|
329
|
+
/** The recovery state around one handler failure, as it is decided. */
|
|
330
|
+
export interface StreamHandlerFailure {
|
|
331
|
+
/**
|
|
332
|
+
* The sequence whose processing failed; `undefined` only for a resync
|
|
333
|
+
* marker that carried no SSE id.
|
|
334
|
+
*/
|
|
335
|
+
seq: number | undefined;
|
|
336
|
+
/** Which awaited step rejected. */
|
|
337
|
+
stage: StreamHandlerStage;
|
|
338
|
+
/** 1-based consecutive failures at this sequence. Resets on any success. */
|
|
339
|
+
attempt: number;
|
|
340
|
+
/** Whether the consumer will reconnect and replay, or throw next. */
|
|
341
|
+
willRetry: boolean;
|
|
342
|
+
/**
|
|
343
|
+
* The sequence the replay resumes AFTER, so the failed frame is delivered
|
|
344
|
+
* again while the server retains it. `undefined` means the replay attaches
|
|
345
|
+
* live and the failed frame is gone: that happens only when nothing has
|
|
346
|
+
* been acknowledged, no `lastEventId` was given, and the failing sequence
|
|
347
|
+
* is not a positive integer to step back from.
|
|
348
|
+
*/
|
|
349
|
+
replayFrom: number | undefined;
|
|
350
|
+
/** The acknowledged checkpoint, which this failure did NOT advance. */
|
|
351
|
+
checkpoint: number | undefined;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* `consumeStreamCheckpointed` gave up after `maxHandlerRetries` consecutive
|
|
355
|
+
* failures at the same sequence (#16247). `checkpoint` is the acknowledged
|
|
356
|
+
* sequence, still behind the failing one, and `replayFrom` is the point a
|
|
357
|
+
* later resume should pass as `lastEventId` to deliver the failed frame
|
|
358
|
+
* again while the server retains it. `cause` is the last rejection your
|
|
359
|
+
* handler produced.
|
|
360
|
+
*/
|
|
361
|
+
export declare class StreamHandlerFailedError extends Error {
|
|
362
|
+
readonly seq: number | undefined;
|
|
363
|
+
readonly stage: StreamHandlerStage;
|
|
364
|
+
readonly attempts: number;
|
|
365
|
+
readonly checkpoint: number | undefined;
|
|
366
|
+
readonly replayFrom: number | undefined;
|
|
367
|
+
constructor(detail: {
|
|
368
|
+
seq: number | undefined;
|
|
369
|
+
stage: StreamHandlerStage;
|
|
370
|
+
attempts: number;
|
|
371
|
+
checkpoint: number | undefined;
|
|
372
|
+
replayFrom: number | undefined;
|
|
373
|
+
}, cause: unknown);
|
|
374
|
+
}
|
|
375
|
+
/** Default for `CheckpointedStreamOptions.maxHandlerRetries`. */
|
|
376
|
+
export declare const DEFAULT_MAX_HANDLER_RETRIES = 3;
|
|
377
|
+
export interface CheckpointedStreamOptions extends ResilientStreamOptions {
|
|
378
|
+
/**
|
|
379
|
+
* Where the acknowledged checkpoint is written. Pass your own object to
|
|
380
|
+
* read it after the consumer returns; omit it and the consumer keeps one
|
|
381
|
+
* internally, which `onCheckpoint` still reports.
|
|
382
|
+
*/
|
|
383
|
+
checkpoint?: StreamCheckpoint;
|
|
384
|
+
/**
|
|
385
|
+
* Consecutive failures at the SAME sequence tolerated before the consumer
|
|
386
|
+
* throws `StreamHandlerFailedError`. Each retry closes the connection and
|
|
387
|
+
* replays from the checkpoint after a jittered backoff (1 s to 30 s). `0`
|
|
388
|
+
* gives up on the first failure. Default `DEFAULT_MAX_HANDLER_RETRIES` (3).
|
|
389
|
+
*/
|
|
390
|
+
maxHandlerRetries?: number;
|
|
391
|
+
/**
|
|
392
|
+
* Called on every handler failure with the recovery state, before the
|
|
393
|
+
* backoff and before any throw. It is the visible signal that work is being
|
|
394
|
+
* replayed rather than lost; it is not awaited and must not throw.
|
|
395
|
+
*/
|
|
396
|
+
onHandlerError?: (error: unknown, failure: StreamHandlerFailure) => void;
|
|
397
|
+
}
|
|
398
|
+
export interface CheckpointedStreamHandlers {
|
|
399
|
+
/**
|
|
400
|
+
* Apply one feed envelope. Awaited: the connection is not read again until
|
|
401
|
+
* it settles. Reject to leave the checkpoint before this event.
|
|
402
|
+
*/
|
|
403
|
+
onEvent: (envelope: FeedEnvelope, seq: number) => void | Promise<void>;
|
|
404
|
+
/**
|
|
405
|
+
* Refresh state after a resync marker. Awaited, so it is a real barrier:
|
|
406
|
+
* the checkpoint moves to the marker only once this resolves. Reject and
|
|
407
|
+
* the refresh is retried under the same bounded policy as an event.
|
|
408
|
+
*/
|
|
409
|
+
onResync?: (marker: ResyncMarker, seq: number | null) => void | Promise<void>;
|
|
410
|
+
/**
|
|
411
|
+
* Persist the checkpoint. Awaited BEFORE the in-memory checkpoint advances,
|
|
412
|
+
* so a failed write leaves the checkpoint where it was and the event is
|
|
413
|
+
* replayed rather than lost.
|
|
414
|
+
*/
|
|
415
|
+
onCheckpoint?: (seq: number, reason: StreamCheckpointReason) => void | Promise<void>;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* The stream consumer for work that must not be silently dropped (#16247):
|
|
419
|
+
* it separates the received cursor from an acknowledged processing
|
|
420
|
+
* checkpoint, and only the checkpoint decides where a reconnect resumes.
|
|
421
|
+
*
|
|
422
|
+
* Ordering, per frame, for `kind: "event"`:
|
|
423
|
+
* 1. `onEvent` is awaited. Nothing is read from the connection while it
|
|
424
|
+
* runs, so a slow handler is backpressure on the socket, never a queue:
|
|
425
|
+
* at most one frame is ever in flight and nothing is buffered on your
|
|
426
|
+
* behalf.
|
|
427
|
+
* 2. `onCheckpoint(seq, "event")` is awaited -- your durable write.
|
|
428
|
+
* 3. Only then does `checkpoint.seq` become `seq`, and only then does the
|
|
429
|
+
* next reconnect resume after it.
|
|
430
|
+
* A rejection at step 1 or 2 leaves the checkpoint BEFORE the event: the
|
|
431
|
+
* connection is closed, a jittered backoff runs, and the consumer reconnects
|
|
432
|
+
* from the checkpoint, which replays the unacknowledged event while the
|
|
433
|
+
* server retains it. `onHandlerError` reports each failure with its attempt
|
|
434
|
+
* number, the replay point and whether another attempt follows. After
|
|
435
|
+
* `maxHandlerRetries` consecutive failures at the same sequence it throws
|
|
436
|
+
* `StreamHandlerFailedError`, carrying the unadvanced checkpoint.
|
|
437
|
+
*
|
|
438
|
+
* A `resync` marker is the same barrier: `onResync` is awaited, then
|
|
439
|
+
* `onCheckpoint(seq, "resync")`, and an interrupted refresh commits nothing,
|
|
440
|
+
* so the recovery is retried instead of being recorded as done. (The
|
|
441
|
+
* fire-and-forget `StreamOptions.onResync` notification is not awaited and is
|
|
442
|
+
* not a barrier -- do not use it as one.)
|
|
443
|
+
*
|
|
444
|
+
* Delivery is AT-LEAST-ONCE. A replay re-delivers every unacknowledged frame,
|
|
445
|
+
* and a handler that succeeded but whose `onCheckpoint` write failed sees its
|
|
446
|
+
* event again. Deduplicate on `seq` (it is monotonic per cluster) or make the
|
|
447
|
+
* side effect idempotent; nothing here can promise exactly-once side effects.
|
|
448
|
+
*
|
|
449
|
+
* `options.cursor` is untouched in meaning: it still tracks the last
|
|
450
|
+
* DELIVERED seq, including frames whose handler later failed, and it rewinds
|
|
451
|
+
* when a replay re-delivers them. Read it for transport progress; never as
|
|
452
|
+
* proof that the work was done.
|
|
453
|
+
*
|
|
454
|
+
* Transport recovery, `Retry-After` handling, permanent 4xx and
|
|
455
|
+
* `StreamProtocolError` behave exactly as in `streamFeedResilient`, which
|
|
456
|
+
* this drives. `StreamReconnectsExhaustedError` and
|
|
457
|
+
* `StreamRetryDeferredError` surface unchanged; their `lastSeq` is the
|
|
458
|
+
* acknowledged checkpoint, because a reconnect can only happen between
|
|
459
|
+
* handlers. Aborting `signal` ends the consumer without throwing: a handler
|
|
460
|
+
* already running is awaited (it is not cancelled for you -- pass the same
|
|
461
|
+
* signal into your own work if you want that), and if it succeeds its
|
|
462
|
+
* checkpoint is committed before the consumer returns.
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* const checkpoint = { seq: await loadCheckpoint() };
|
|
466
|
+
* await consumeStreamCheckpointed(client, {
|
|
467
|
+
* onEvent: async (envelope, seq) => { await applyOnce(seq, envelope); },
|
|
468
|
+
* onResync: async () => { await refetchCurrentState(); },
|
|
469
|
+
* onCheckpoint: async (seq) => { await saveCheckpoint(seq); },
|
|
470
|
+
* }, {
|
|
471
|
+
* event: ["WhaleTradesInserted"],
|
|
472
|
+
* lastEventId: checkpoint.seq,
|
|
473
|
+
* checkpoint,
|
|
474
|
+
* signal: controller.signal,
|
|
475
|
+
* onHandlerError: (error, failure) =>
|
|
476
|
+
* console.warn("replaying", failure.seq, failure.attempt, failure.willRetry, error),
|
|
477
|
+
* });
|
|
478
|
+
*/
|
|
479
|
+
export declare function consumeStreamCheckpointed(client: OxinsiderApiClient, handlers: CheckpointedStreamHandlers, options?: CheckpointedStreamOptions): Promise<void>;
|
|
480
|
+
export interface ParsedSseFrame {
|
|
175
481
|
event?: string;
|
|
176
482
|
id?: number;
|
|
177
483
|
data: string;
|
|
178
484
|
}
|
|
179
485
|
/** Parse one SSE frame (without the trailing blank line). */
|
|
180
486
|
export declare function parseSseFrame(raw: string): ParsedSseFrame | null;
|
|
181
|
-
|
|
487
|
+
/**
|
|
488
|
+
* Turn one parsed SSE frame into a `StreamEvent`, or throw
|
|
489
|
+
* `StreamProtocolError` (#16248). `lastSeq` is only carried onto the error.
|
|
490
|
+
*/
|
|
491
|
+
export declare function decodeStreamFrame(parsed: ParsedSseFrame, lastSeq: number | undefined): StreamEvent;
|
|
182
492
|
//# sourceMappingURL=stream.d.ts.map
|
package/dist/sdk/stream.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../sdk/src/stream.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../sdk/src/stream.ts"],"names":[],"mappings":"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"}
|