@0xinsider/sdk 0.14.0-bootstrap.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/LICENSE +21 -0
- package/README.md +674 -0
- package/dist/client.d.ts +1652 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +2127 -0
- package/dist/client.js.map +1 -0
- package/dist/data-quality.d.ts +74 -0
- package/dist/data-quality.d.ts.map +1 -0
- package/dist/data-quality.js +68 -0
- package/dist/data-quality.js.map +1 -0
- package/dist/errors.d.ts +400 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +700 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/pagination.d.ts +196 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +208 -0
- package/dist/pagination.js.map +1 -0
- package/dist/provenance.d.ts +8 -0
- package/dist/provenance.d.ts.map +1 -0
- package/dist/provenance.js +15 -0
- package/dist/provenance.js.map +1 -0
- package/dist/retry.d.ts +68 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +125 -0
- package/dist/retry.js.map +1 -0
- package/dist/schema.d.ts +4910 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +7 -0
- package/dist/schema.js.map +1 -0
- package/dist/stream.d.ts +509 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +932 -0
- package/dist/stream.js.map +1 -0
- package/dist/webhooks.d.ts +314 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +153 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +64 -0
package/dist/stream.d.ts
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE consumer for `GET /api/v1/stream`.
|
|
3
|
+
*
|
|
4
|
+
* The endpoint forwards the platform's live feed envelopes as Server-Sent
|
|
5
|
+
* Events. Source of truth: `web/public/api/v1/openapi.json` -> paths./api/v1/stream.
|
|
6
|
+
*
|
|
7
|
+
* Wire format (per the spec's response description):
|
|
8
|
+
* - Each data frame is `id: <seq>\ndata: <json-envelope>\n\n`, where the JSON
|
|
9
|
+
* envelope is `{ seq, published_at, type, ...event-specific }`. The SSE id
|
|
10
|
+
* equals the envelope `seq`.
|
|
11
|
+
* - A resync marker is `event: resync\nid: <seq>\ndata: <json>\n\n`, where the
|
|
12
|
+
* JSON is `{ type: "resync", completeness, from_sequence, to_sequence }`.
|
|
13
|
+
* It means the requested resume point is outside the retained window or a
|
|
14
|
+
* live sequence gap was observed; treat it as "refetch current state".
|
|
15
|
+
* - Idle connections emit `: keep-alive` comment lines (ignored).
|
|
16
|
+
*
|
|
17
|
+
* Resume is via the `Last-Event-ID` header set to the last `seq` you processed;
|
|
18
|
+
* the spec also accepts `last_event_id` / `seq` query fallbacks. This consumer
|
|
19
|
+
* sends the header and auto-tracks the last seen seq so a caller-driven
|
|
20
|
+
* reconnect resumes from the right place.
|
|
21
|
+
*
|
|
22
|
+
* Filters (per-connection, subscribe-time): `event` (comma-separated frame
|
|
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 larger than `maxFrameBytes` (default 1 MiB), whether or not its
|
|
35
|
+
* blank-line delimiter has arrived, is `frame_too_large` before it is
|
|
36
|
+
* parsed (#16644); the reader is 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
|
+
* - A terminal `event: error` frame (the key was revoked, the account
|
|
42
|
+
* lapsed, or the credential store could not confirm the key) throws the
|
|
43
|
+
* typed `OxinsiderApiError` it carries and is never yielded (#16546);
|
|
44
|
+
* `retry: false` is permanent to the resilient consumers.
|
|
45
|
+
* Comment lines (`: keep-alive`), LF and CRLF framing, unknown SSE fields
|
|
46
|
+
* and unknown-but-valid envelope `type`s are compatible as before.
|
|
47
|
+
*/
|
|
48
|
+
import { type Grade, type OxinsiderApiClient } from "./client.js";
|
|
49
|
+
/** A live feed envelope frame: `{ seq, published_at, type, ...payload }`. */
|
|
50
|
+
export interface FeedEnvelope {
|
|
51
|
+
/** Cluster-shared monotonic sequence id; also the SSE event id. */
|
|
52
|
+
seq: number;
|
|
53
|
+
/** ISO-8601 publish time, when present. */
|
|
54
|
+
published_at?: string;
|
|
55
|
+
/** Frame wire type, e.g. `"WhaleTradesInserted"`. */
|
|
56
|
+
type: string;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
}
|
|
59
|
+
/** A resync marker frame (SSE `event: resync`). */
|
|
60
|
+
export interface ResyncMarker {
|
|
61
|
+
type: "resync";
|
|
62
|
+
completeness?: {
|
|
63
|
+
status?: string;
|
|
64
|
+
reason?: string;
|
|
65
|
+
[key: string]: unknown;
|
|
66
|
+
};
|
|
67
|
+
from_sequence?: number;
|
|
68
|
+
to_sequence?: number;
|
|
69
|
+
[key: string]: unknown;
|
|
70
|
+
}
|
|
71
|
+
export interface StreamFilters {
|
|
72
|
+
/**
|
|
73
|
+
* Subscribe only to these frame wire types. Sent as a comma-separated
|
|
74
|
+
* `event` query param. Empty/omitted = all frames.
|
|
75
|
+
*/
|
|
76
|
+
event?: readonly string[];
|
|
77
|
+
/** Subscribe only to frames for this market (raw provider id or `mkt_*`). */
|
|
78
|
+
condition_id?: string;
|
|
79
|
+
/** Only deliver frames carrying a grade at or above this threshold. */
|
|
80
|
+
min_grade?: Grade;
|
|
81
|
+
}
|
|
82
|
+
export interface StreamOptions extends StreamFilters {
|
|
83
|
+
/**
|
|
84
|
+
* Resume after this cluster-shared sequence id (sets `Last-Event-ID`). It
|
|
85
|
+
* remains valid across replicas and process restarts while retained. When
|
|
86
|
+
* omitted the stream starts from the live head.
|
|
87
|
+
*/
|
|
88
|
+
lastEventId?: number | string;
|
|
89
|
+
/** Cooperative cancellation; abort to close the stream. */
|
|
90
|
+
signal?: AbortSignal;
|
|
91
|
+
/** Invoked once for the resync marker frame, if one is emitted. */
|
|
92
|
+
onResync?: (marker: ResyncMarker) => void;
|
|
93
|
+
/**
|
|
94
|
+
* Optional cursor object whose `seq` is updated to the last DELIVERED
|
|
95
|
+
* envelope `seq` as frames arrive. Pass the same object back as
|
|
96
|
+
* `lastEventId: cursor.seq` on reconnect to resume from where you left off.
|
|
97
|
+
*
|
|
98
|
+
* Received, not processed (#16247). It is written before the frame reaches
|
|
99
|
+
* your code, so it says the frame arrived and nothing about whether your
|
|
100
|
+
* handling of it succeeded: resuming from it after a handler failure skips
|
|
101
|
+
* that event. When losing an event would lose work, drive the stream with
|
|
102
|
+
* `consumeStreamCheckpointed`, whose `StreamCheckpoint` advances only after
|
|
103
|
+
* the handler and your durable write resolve, and keep this cursor for
|
|
104
|
+
* transport progress.
|
|
105
|
+
*/
|
|
106
|
+
cursor?: {
|
|
107
|
+
seq?: number;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Byte ceiling for one undelivered frame (#16248). Default
|
|
111
|
+
* `DEFAULT_MAX_STREAM_FRAME_BYTES` (1 MiB). A frame larger than this,
|
|
112
|
+
* delimited or not, ends the connection with `StreamProtocolError`
|
|
113
|
+
* (`frame_too_large`) before it is parsed or yielded, and the reader is
|
|
114
|
+
* released (#16644).
|
|
115
|
+
* A positive finite integer; the largest real frame is a few KB.
|
|
116
|
+
*/
|
|
117
|
+
maxFrameBytes?: number;
|
|
118
|
+
}
|
|
119
|
+
/** Default for `StreamOptions.maxFrameBytes`: 1 MiB. */
|
|
120
|
+
export declare const DEFAULT_MAX_STREAM_FRAME_BYTES = 1048576;
|
|
121
|
+
/** What the stream did that the SSE contract does not allow. */
|
|
122
|
+
export type StreamProtocolErrorReason =
|
|
123
|
+
/** A 2xx whose `Content-Type` is not `text/event-stream`. */
|
|
124
|
+
"unexpected_media_type"
|
|
125
|
+
/** A data frame whose payload is not JSON. */
|
|
126
|
+
| "invalid_json"
|
|
127
|
+
/** A data frame whose payload is JSON but not an object (or is `null`, an array). */
|
|
128
|
+
| "invalid_envelope"
|
|
129
|
+
/** A data frame with no finite `seq` in the envelope and no finite SSE `id`. */
|
|
130
|
+
| "unusable_sequence"
|
|
131
|
+
/** A resync frame whose payload is not an object, or whose `type` is not `resync`. */
|
|
132
|
+
| "invalid_resync"
|
|
133
|
+
/** A frame, delimited or not, is larger than `maxFrameBytes`. */
|
|
134
|
+
| "frame_too_large";
|
|
135
|
+
/**
|
|
136
|
+
* The stream broke the SSE contract (#16248). The connection is closed and
|
|
137
|
+
* the reader released before this is thrown. `lastSeq` is the last sequence
|
|
138
|
+
* delivered on this connection, or `undefined` when none was: no malformed
|
|
139
|
+
* frame moves the cursor. `frameId` is the SSE `id` of the offending frame
|
|
140
|
+
* when it carried one, `event` its SSE event name, `bytes` its size, and
|
|
141
|
+
* `mediaType` the response's `Content-Type` for `unexpected_media_type`. The
|
|
142
|
+
* raw payload is deliberately not carried: it may hold data you would not
|
|
143
|
+
* want in a log, and `frameId` plus `lastSeq` name the frame exactly.
|
|
144
|
+
*
|
|
145
|
+
* `streamFeedResilient` treats this as permanent: reconnecting from
|
|
146
|
+
* `lastSeq` would replay the same frame while the server retains it. Decide:
|
|
147
|
+
* resume from `lastSeq` later, resume after `frameId` to skip it, or refetch
|
|
148
|
+
* state and attach live.
|
|
149
|
+
*/
|
|
150
|
+
export declare class StreamProtocolError extends Error {
|
|
151
|
+
readonly reason: StreamProtocolErrorReason;
|
|
152
|
+
readonly lastSeq: number | undefined;
|
|
153
|
+
readonly frameId: number | undefined;
|
|
154
|
+
readonly event: string | undefined;
|
|
155
|
+
readonly bytes: number | undefined;
|
|
156
|
+
readonly mediaType: string | undefined;
|
|
157
|
+
constructor(reason: StreamProtocolErrorReason, detail: {
|
|
158
|
+
lastSeq: number | undefined;
|
|
159
|
+
frameId?: number;
|
|
160
|
+
event?: string;
|
|
161
|
+
bytes?: number;
|
|
162
|
+
mediaType?: string | null;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/** `Content-Type` names an event stream: `text/event-stream`, with or without parameters. */
|
|
166
|
+
export declare function isEventStreamMediaType(contentType: string | null): boolean;
|
|
167
|
+
/** One yielded item from the stream iterator. */
|
|
168
|
+
export type StreamEvent = {
|
|
169
|
+
kind: "event";
|
|
170
|
+
seq: number;
|
|
171
|
+
envelope: FeedEnvelope;
|
|
172
|
+
} | {
|
|
173
|
+
kind: "resync";
|
|
174
|
+
seq: number | null;
|
|
175
|
+
marker: ResyncMarker;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Open the stream and async-iterate its frames. Yields a discriminated
|
|
179
|
+
* `StreamEvent`: `kind: "event"` carries the `FeedEnvelope`, `kind: "resync"`
|
|
180
|
+
* carries the `ResyncMarker`.
|
|
181
|
+
*
|
|
182
|
+
* Pass `options.cursor` (a `{ seq?: number }` object) to have the last
|
|
183
|
+
* delivered `seq` written back as frames arrive; reconnect with
|
|
184
|
+
* `lastEventId: cursor.seq` to resume after a transport drop.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* for await (const frame of streamFeed(client, { event: ["WhaleTradesInserted"], min_grade: "S" })) {
|
|
188
|
+
* if (frame.kind === "event") console.log(frame.envelope.type, frame.seq);
|
|
189
|
+
* }
|
|
190
|
+
*/
|
|
191
|
+
export declare function streamFeed(client: OxinsiderApiClient, options?: StreamOptions): AsyncGenerator<StreamEvent, void, undefined>;
|
|
192
|
+
export interface ResilientStreamOptions extends StreamOptions {
|
|
193
|
+
/**
|
|
194
|
+
* Consecutive failed connections tolerated before giving up with
|
|
195
|
+
* `StreamReconnectsExhaustedError`. A connection that delivers any frame
|
|
196
|
+
* resets the count. Default `DEFAULT_MAX_STREAM_RECONNECTS` (10).
|
|
197
|
+
*/
|
|
198
|
+
maxReconnects?: number;
|
|
199
|
+
/**
|
|
200
|
+
* Called before each reconnect's backoff: the 1-based consecutive attempt,
|
|
201
|
+
* the seq the reconnect resumes after (`undefined` attaches live), and why
|
|
202
|
+
* the previous connection ended (`undefined` for a clean server close).
|
|
203
|
+
*/
|
|
204
|
+
onReconnect?: (attempt: number, lastSeq: number | undefined, cause: unknown) => void;
|
|
205
|
+
/**
|
|
206
|
+
* The longest server-requested wait (`Retry-After` or `retry_at`) the loop holds
|
|
207
|
+
* in-process, in ms. Default `DEFAULT_MAX_STREAM_RETRY_AFTER_MS` (60 000,
|
|
208
|
+
* the REST client's ceiling). A refusal asking for longer ends the loop
|
|
209
|
+
* with `StreamRetryDeferredError`, which carries the not-before instant
|
|
210
|
+
* (`retryAt`) and the seq to resume after (`lastSeq`), so the wait is
|
|
211
|
+
* yours to schedule and no reconnect is spent on it. `Infinity` opts into
|
|
212
|
+
* waiting however long the server says, in timer-sized chunks; it can hold
|
|
213
|
+
* the process for days on a `monthly_quota_exceeded` refusal, which is why
|
|
214
|
+
* it is not the default (#16249).
|
|
215
|
+
*/
|
|
216
|
+
maxRetryAfterMs?: number;
|
|
217
|
+
}
|
|
218
|
+
/** Default for `ResilientStreamOptions.maxReconnects`. */
|
|
219
|
+
export declare const DEFAULT_MAX_STREAM_RECONNECTS = 10;
|
|
220
|
+
/** Default for `ResilientStreamOptions.maxRetryAfterMs`. */
|
|
221
|
+
export declare const DEFAULT_MAX_STREAM_RETRY_AFTER_MS = 60000;
|
|
222
|
+
/**
|
|
223
|
+
* `streamFeedResilient` gave up after `maxReconnects` consecutive failed
|
|
224
|
+
* connections. `lastSeq` is the seq to resume after (pass it as `lastEventId`
|
|
225
|
+
* later); `cause` is the last connection's failure.
|
|
226
|
+
*/
|
|
227
|
+
export declare class StreamReconnectsExhaustedError extends Error {
|
|
228
|
+
readonly lastSeq: number | undefined;
|
|
229
|
+
readonly attempts: number;
|
|
230
|
+
constructor(attempts: number, lastSeq: number | undefined, cause: unknown);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* `streamFeedResilient` received a server-requested wait longer than
|
|
234
|
+
* `maxRetryAfterMs`, so the wait is yours to schedule (#16249). `retryAt` is
|
|
235
|
+
* the server's not-before instant as this client read it (the header's
|
|
236
|
+
* seconds added to the local clock, the header's HTTP-date, or terminal
|
|
237
|
+
* `retry_at` when no usable header exists); `cause` is
|
|
238
|
+
* the refusal, whose `retryAt` (from the body's `retry_at`) is the server's
|
|
239
|
+
* own clock reading of the same instant. `lastSeq` is the seq to resume after:
|
|
240
|
+
* pass it as `lastEventId` when you reconnect at `retryAt`. `attempts` is how
|
|
241
|
+
* many consecutive failed connections preceded this one; the refusal itself
|
|
242
|
+
* spent none of `maxReconnects`.
|
|
243
|
+
*
|
|
244
|
+
* Nothing here was clamped: a wait the timer cannot hold is never shortened
|
|
245
|
+
* into an earlier reconnect.
|
|
246
|
+
*/
|
|
247
|
+
export declare class StreamRetryDeferredError extends Error {
|
|
248
|
+
readonly retryAt: Date;
|
|
249
|
+
readonly retryAfterMs: number;
|
|
250
|
+
readonly lastSeq: number | undefined;
|
|
251
|
+
readonly attempts: number;
|
|
252
|
+
constructor(retryAfterMs: number, lastSeq: number | undefined, attempts: number, cause: unknown);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* `streamFeed` with the reconnect-and-resume loop built in (#14286).
|
|
256
|
+
*
|
|
257
|
+
* - A clean server close, a network error, a 429 or a 5xx reconnects,
|
|
258
|
+
* resuming after the last delivered seq (`Last-Event-ID`). Before any frame
|
|
259
|
+
* arrives it resumes from `lastEventId`, or attaches live when that is unset.
|
|
260
|
+
* - The wait is `Retry-After` (delta-seconds or an HTTP-date) plus jitter when
|
|
261
|
+
* the refusal carries one, otherwise a jittered backoff from 1 s capped at
|
|
262
|
+
* 30 s. A `Retry-After` past `maxRetryAfterMs` (60 s by default) is not
|
|
263
|
+
* waited out: the loop throws `StreamRetryDeferredError` with `retryAt` and
|
|
264
|
+
* `lastSeq`, spending no reconnect, and never clamps the wait to an earlier
|
|
265
|
+
* one (#16249).
|
|
266
|
+
* - Any other 4xx (400, 401, 402, 403, 423) is thrown at once: it cannot heal
|
|
267
|
+
* on its own. So is `StreamProtocolError` (#16248): a resume from
|
|
268
|
+
* `lastSeq` would replay the malformed frame, so the decision is yours.
|
|
269
|
+
* - After `maxReconnects` consecutive connections that delivered nothing, it
|
|
270
|
+
* throws `StreamReconnectsExhaustedError` carrying `lastSeq`.
|
|
271
|
+
* - `resync` markers are yielded unchanged, and `onResync` still fires. The
|
|
272
|
+
* marker's `id` becomes the resume cursor, as the server intends, so a
|
|
273
|
+
* reconnect after one does not request the aged window again.
|
|
274
|
+
* - Aborting `signal` ends the iterator without throwing, during a connection
|
|
275
|
+
* or a backoff. Each connection's body reader is cancelled when it ends, so
|
|
276
|
+
* reconnects do not accumulate sockets.
|
|
277
|
+
* - No request deadline applies, as with `streamFeed`.
|
|
278
|
+
*
|
|
279
|
+
* `options.cursor`, when passed, tracks the last delivered seq across every
|
|
280
|
+
* connection -- delivered, not processed (#16247). This loop resumes from it,
|
|
281
|
+
* so a consumer whose handler can fail should drive the stream with
|
|
282
|
+
* `consumeStreamCheckpointed` instead, which resumes from an acknowledged
|
|
283
|
+
* checkpoint and replays the event it failed on.
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* const controller = new AbortController();
|
|
287
|
+
* for await (const frame of streamFeedResilient(client, {
|
|
288
|
+
* event: ["WhaleTradesInserted"],
|
|
289
|
+
* signal: controller.signal,
|
|
290
|
+
* onReconnect: (attempt, lastSeq, cause) => console.warn("reconnecting", attempt, lastSeq, cause),
|
|
291
|
+
* })) {
|
|
292
|
+
* if (frame.kind === "resync") await refetchState();
|
|
293
|
+
* else handle(frame.envelope);
|
|
294
|
+
* }
|
|
295
|
+
*/
|
|
296
|
+
export declare function streamFeedResilient(client: OxinsiderApiClient, options?: ResilientStreamOptions): AsyncGenerator<StreamEvent, void, undefined>;
|
|
297
|
+
/**
|
|
298
|
+
* Callback-style stream consumer for environments where an async iterator is
|
|
299
|
+
* awkward. Returns a promise that resolves when the stream ends (or rejects on
|
|
300
|
+
* error / abort). Pass a `signal` to stop it.
|
|
301
|
+
*
|
|
302
|
+
* Delivery, not processing (#16247): `options.cursor` is written by
|
|
303
|
+
* `streamFeed` BEFORE the frame is yielded, so it has already moved past an
|
|
304
|
+
* event whose `onEvent` then throws. Reconnecting from it skips that event.
|
|
305
|
+
* For a consumer that must not lose work, use `consumeStreamCheckpointed`,
|
|
306
|
+
* which advances an acknowledged checkpoint only after the handler and your
|
|
307
|
+
* own durable write have both resolved.
|
|
308
|
+
*/
|
|
309
|
+
export declare function consumeStream(client: OxinsiderApiClient, handlers: {
|
|
310
|
+
onEvent?: (envelope: FeedEnvelope, seq: number) => void | Promise<void>;
|
|
311
|
+
onResync?: (marker: ResyncMarker, seq: number | null) => void | Promise<void>;
|
|
312
|
+
}, options?: StreamOptions): Promise<void>;
|
|
313
|
+
/**
|
|
314
|
+
* An acknowledged processing checkpoint (#16247): the last `seq` whose
|
|
315
|
+
* handling COMPLETED, which is not the same thing as the last `seq` that
|
|
316
|
+
* arrived. `StreamOptions.cursor` is the received cursor -- transport
|
|
317
|
+
* progress, written before the frame is handed to you. This is the processed
|
|
318
|
+
* one, written after your handler and your own durable write have resolved.
|
|
319
|
+
*
|
|
320
|
+
* Own the object if you persist the checkpoint yourself: pass it in, read
|
|
321
|
+
* `seq` after the consumer returns or throws, and pass the stored value back
|
|
322
|
+
* as `lastEventId` when you resume in a later process.
|
|
323
|
+
*/
|
|
324
|
+
export interface StreamCheckpoint {
|
|
325
|
+
/** The last acknowledged sequence, or `undefined` until one is acknowledged. */
|
|
326
|
+
seq?: number;
|
|
327
|
+
}
|
|
328
|
+
/** What the checkpoint advanced past: a feed envelope, or a resync refresh. */
|
|
329
|
+
export type StreamCheckpointReason = "event" | "resync";
|
|
330
|
+
/**
|
|
331
|
+
* Which awaited step rejected: your event handler, your resync refresh, or
|
|
332
|
+
* your `onCheckpoint` durable write.
|
|
333
|
+
*/
|
|
334
|
+
export type StreamHandlerStage = "event" | "resync" | "checkpoint";
|
|
335
|
+
/** The recovery state around one handler failure, as it is decided. */
|
|
336
|
+
export interface StreamHandlerFailure {
|
|
337
|
+
/**
|
|
338
|
+
* The sequence whose processing failed; `undefined` only for a resync
|
|
339
|
+
* marker that carried no SSE id.
|
|
340
|
+
*/
|
|
341
|
+
seq: number | undefined;
|
|
342
|
+
/** Which awaited step rejected. */
|
|
343
|
+
stage: StreamHandlerStage;
|
|
344
|
+
/** 1-based consecutive failures at this sequence. Resets on any success. */
|
|
345
|
+
attempt: number;
|
|
346
|
+
/** Whether replay is planned; false means exhaustion or clean cancellation. */
|
|
347
|
+
willRetry: boolean;
|
|
348
|
+
/**
|
|
349
|
+
* Present and true when caller cancellation has stopped the consumer at
|
|
350
|
+
* this observation. It does not claim cancellation caused the rejection.
|
|
351
|
+
*/
|
|
352
|
+
cancelled?: boolean;
|
|
353
|
+
/**
|
|
354
|
+
* The sequence the replay resumes AFTER, so the failed frame is delivered
|
|
355
|
+
* again while the server retains it. `undefined` means the replay attaches
|
|
356
|
+
* live and the failed frame is gone: that happens only when nothing has
|
|
357
|
+
* been acknowledged, no `lastEventId` was given, and the failing sequence
|
|
358
|
+
* is not a positive integer to step back from.
|
|
359
|
+
*/
|
|
360
|
+
replayFrom: number | undefined;
|
|
361
|
+
/** The acknowledged checkpoint, which this failure did NOT advance. */
|
|
362
|
+
checkpoint: number | undefined;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* `consumeStreamCheckpointed` gave up after `maxHandlerRetries` consecutive
|
|
366
|
+
* failures at the same sequence (#16247). `checkpoint` is the acknowledged
|
|
367
|
+
* sequence, still behind the failing one, and `replayFrom` is the point a
|
|
368
|
+
* later resume should pass as `lastEventId` to deliver the failed frame
|
|
369
|
+
* again while the server retains it. `cause` is the last rejection your
|
|
370
|
+
* handler produced.
|
|
371
|
+
*/
|
|
372
|
+
export declare class StreamHandlerFailedError extends Error {
|
|
373
|
+
readonly seq: number | undefined;
|
|
374
|
+
readonly stage: StreamHandlerStage;
|
|
375
|
+
readonly attempts: number;
|
|
376
|
+
readonly checkpoint: number | undefined;
|
|
377
|
+
readonly replayFrom: number | undefined;
|
|
378
|
+
constructor(detail: {
|
|
379
|
+
seq: number | undefined;
|
|
380
|
+
stage: StreamHandlerStage;
|
|
381
|
+
attempts: number;
|
|
382
|
+
checkpoint: number | undefined;
|
|
383
|
+
replayFrom: number | undefined;
|
|
384
|
+
}, cause: unknown);
|
|
385
|
+
}
|
|
386
|
+
/** Default for `CheckpointedStreamOptions.maxHandlerRetries`. */
|
|
387
|
+
export declare const DEFAULT_MAX_HANDLER_RETRIES = 3;
|
|
388
|
+
export interface CheckpointedStreamOptions extends ResilientStreamOptions {
|
|
389
|
+
/**
|
|
390
|
+
* Where the acknowledged checkpoint is written. Pass your own object to
|
|
391
|
+
* read it after the consumer returns; omit it and the consumer keeps one
|
|
392
|
+
* internally, which `onCheckpoint` still reports.
|
|
393
|
+
*/
|
|
394
|
+
checkpoint?: StreamCheckpoint;
|
|
395
|
+
/**
|
|
396
|
+
* Consecutive failures at the SAME sequence tolerated before the consumer
|
|
397
|
+
* throws `StreamHandlerFailedError`. Each retry closes the connection and
|
|
398
|
+
* replays from the checkpoint after a jittered backoff (1 s to 30 s). `0`
|
|
399
|
+
* gives up on the first failure. Default `DEFAULT_MAX_HANDLER_RETRIES` (3).
|
|
400
|
+
*/
|
|
401
|
+
maxHandlerRetries?: number;
|
|
402
|
+
/**
|
|
403
|
+
* Called on every handler failure with the recovery state, before backoff,
|
|
404
|
+
* exhaustion, or a clean cancellation return. Cancellation retains the
|
|
405
|
+
* original error with `willRetry: false` and `cancelled: true`, without
|
|
406
|
+
* spending a retry. It is not awaited and must not throw.
|
|
407
|
+
*/
|
|
408
|
+
onHandlerError?: (error: unknown, failure: StreamHandlerFailure) => void;
|
|
409
|
+
}
|
|
410
|
+
export interface CheckpointedStreamHandlers {
|
|
411
|
+
/**
|
|
412
|
+
* Apply one feed envelope. Awaited: the connection is not read again until
|
|
413
|
+
* it settles. Reject to leave the checkpoint before this event.
|
|
414
|
+
*/
|
|
415
|
+
onEvent: (envelope: FeedEnvelope, seq: number) => void | Promise<void>;
|
|
416
|
+
/**
|
|
417
|
+
* Refresh state after a resync marker. Awaited, so it is a real barrier:
|
|
418
|
+
* the checkpoint moves to the marker only once this resolves. Reject and
|
|
419
|
+
* the refresh is retried under the same bounded policy as an event.
|
|
420
|
+
*/
|
|
421
|
+
onResync?: (marker: ResyncMarker, seq: number | null) => void | Promise<void>;
|
|
422
|
+
/**
|
|
423
|
+
* Persist the checkpoint. Awaited BEFORE the in-memory checkpoint advances,
|
|
424
|
+
* so a failed write leaves the checkpoint where it was and the event is
|
|
425
|
+
* replayed rather than lost.
|
|
426
|
+
*/
|
|
427
|
+
onCheckpoint?: (seq: number, reason: StreamCheckpointReason) => void | Promise<void>;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* The stream consumer for work that must not be silently dropped (#16247):
|
|
431
|
+
* it separates the received cursor from an acknowledged processing
|
|
432
|
+
* checkpoint, and only the checkpoint decides where a reconnect resumes.
|
|
433
|
+
*
|
|
434
|
+
* Ordering, per frame, for `kind: "event"`:
|
|
435
|
+
* 1. `onEvent` is awaited. Nothing is read from the connection while it
|
|
436
|
+
* runs, so a slow handler is backpressure on the socket, never a queue:
|
|
437
|
+
* at most one frame is ever in flight and nothing is buffered on your
|
|
438
|
+
* behalf.
|
|
439
|
+
* 2. `onCheckpoint(seq, "event")` is awaited -- your durable write.
|
|
440
|
+
* 3. Only then does `checkpoint.seq` become `seq`, and only then does the
|
|
441
|
+
* next reconnect resume after it.
|
|
442
|
+
* A rejection at step 1 or 2 leaves the checkpoint BEFORE the event: the
|
|
443
|
+
* connection is closed, a jittered backoff runs, and the consumer reconnects
|
|
444
|
+
* from the checkpoint, which replays the unacknowledged event while the
|
|
445
|
+
* server retains it. `onHandlerError` reports each failure with its attempt
|
|
446
|
+
* number, the replay point and whether another attempt follows. After
|
|
447
|
+
* `maxHandlerRetries` consecutive failures at the same sequence it throws
|
|
448
|
+
* `StreamHandlerFailedError`, carrying the unadvanced checkpoint.
|
|
449
|
+
*
|
|
450
|
+
* A `resync` marker is the same barrier: `onResync` is awaited, then
|
|
451
|
+
* `onCheckpoint(seq, "resync")`, and an interrupted refresh commits nothing,
|
|
452
|
+
* so the recovery is retried instead of being recorded as done. (The
|
|
453
|
+
* fire-and-forget `StreamOptions.onResync` notification is not awaited and is
|
|
454
|
+
* not a barrier -- do not use it as one.)
|
|
455
|
+
*
|
|
456
|
+
* Delivery is AT-LEAST-ONCE. A replay re-delivers every unacknowledged frame,
|
|
457
|
+
* and a handler that succeeded but whose `onCheckpoint` write failed sees its
|
|
458
|
+
* event again. Deduplicate on `seq` (it is monotonic per cluster) or make the
|
|
459
|
+
* side effect idempotent; nothing here can promise exactly-once side effects.
|
|
460
|
+
*
|
|
461
|
+
* `options.cursor` is untouched in meaning: it still tracks the last
|
|
462
|
+
* DELIVERED seq, including frames whose handler later failed, and it rewinds
|
|
463
|
+
* when a replay re-delivers them. Read it for transport progress; never as
|
|
464
|
+
* proof that the work was done.
|
|
465
|
+
*
|
|
466
|
+
* Transport recovery, `Retry-After` handling, permanent 4xx and
|
|
467
|
+
* `StreamProtocolError` behave exactly as in `streamFeedResilient`, which
|
|
468
|
+
* this drives. `StreamReconnectsExhaustedError` and
|
|
469
|
+
* `StreamRetryDeferredError` surface unchanged; their `lastSeq` is the
|
|
470
|
+
* acknowledged checkpoint, because a reconnect can only happen between
|
|
471
|
+
* handlers. Aborting `signal` ends the consumer without throwing: a handler
|
|
472
|
+
* already running is awaited (it is not cancelled for you -- pass the same
|
|
473
|
+
* signal into your own work if you want that), and if it succeeds its
|
|
474
|
+
* checkpoint is committed before the consumer returns. If an awaited event,
|
|
475
|
+
* resync, or checkpoint callback rejects during cancellation, the checkpoint
|
|
476
|
+
* stays unchanged and `onHandlerError` reports the original rejection with
|
|
477
|
+
* `willRetry: false` and `cancelled: true`; the consumer returns even when
|
|
478
|
+
* handler retries are disabled or exhausted. A coincident unrelated failure
|
|
479
|
+
* is still reported, without claiming cancellation caused it.
|
|
480
|
+
*
|
|
481
|
+
* @example
|
|
482
|
+
* const checkpoint = { seq: await loadCheckpoint() };
|
|
483
|
+
* await consumeStreamCheckpointed(client, {
|
|
484
|
+
* onEvent: async (envelope, seq) => { await applyOnce(seq, envelope); },
|
|
485
|
+
* onResync: async () => { await refetchCurrentState(); },
|
|
486
|
+
* onCheckpoint: async (seq) => { await saveCheckpoint(seq); },
|
|
487
|
+
* }, {
|
|
488
|
+
* event: ["WhaleTradesInserted"],
|
|
489
|
+
* lastEventId: checkpoint.seq,
|
|
490
|
+
* checkpoint,
|
|
491
|
+
* signal: controller.signal,
|
|
492
|
+
* onHandlerError: (error, failure) =>
|
|
493
|
+
* console.warn("handler failed", failure.seq, failure.attempt, failure.willRetry, error),
|
|
494
|
+
* });
|
|
495
|
+
*/
|
|
496
|
+
export declare function consumeStreamCheckpointed(client: OxinsiderApiClient, handlers: CheckpointedStreamHandlers, options?: CheckpointedStreamOptions): Promise<void>;
|
|
497
|
+
export interface ParsedSseFrame {
|
|
498
|
+
event?: string;
|
|
499
|
+
id?: number;
|
|
500
|
+
data: string;
|
|
501
|
+
}
|
|
502
|
+
/** Parse one SSE frame (without the trailing blank line). */
|
|
503
|
+
export declare function parseSseFrame(raw: string): ParsedSseFrame | null;
|
|
504
|
+
/**
|
|
505
|
+
* Turn one parsed SSE frame into a `StreamEvent`, or throw
|
|
506
|
+
* `StreamProtocolError` (#16248). `lastSeq` is only carried onto the error.
|
|
507
|
+
*/
|
|
508
|
+
export declare function decodeStreamFrame(parsed: ParsedSseFrame, lastSeq: number | undefined): StreamEvent;
|
|
509
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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"}
|