thetadatadx 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +267 -0
- package/index.d.ts +7487 -0
- package/index.js +685 -0
- package/package.json +50 -0
- package/record_batch_forwarder.js +20 -0
- package/streaming-session.d.ts +266 -0
- package/streaming-session.js +789 -0
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "thetadatadx",
|
|
3
|
+
"version": "13.0.0",
|
|
4
|
+
"description": "Native ThetaData market-data SDK for Node.js",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/userFRM/ThetaDataDx"
|
|
9
|
+
},
|
|
10
|
+
"main": "streaming-session.js",
|
|
11
|
+
"types": "streaming-session.d.ts",
|
|
12
|
+
"napi": {
|
|
13
|
+
"name": "thetadatadx",
|
|
14
|
+
"triples": {
|
|
15
|
+
"defaults": false,
|
|
16
|
+
"additional": [
|
|
17
|
+
"x86_64-unknown-linux-gnu",
|
|
18
|
+
"aarch64-apple-darwin",
|
|
19
|
+
"x86_64-pc-windows-msvc"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "napi build --platform --release && node scripts/postbuild_alias_contract.mjs",
|
|
25
|
+
"build:debug": "napi build --platform && node scripts/postbuild_alias_contract.mjs",
|
|
26
|
+
"test": "node scripts/run_tests.mjs",
|
|
27
|
+
"version": "napi version"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@napi-rs/cli": "^3.6.2",
|
|
31
|
+
"@types/node": "26.1.0",
|
|
32
|
+
"apache-arrow": "21.1.0",
|
|
33
|
+
"typescript": "6.0.3"
|
|
34
|
+
},
|
|
35
|
+
"optionalDependencies": {
|
|
36
|
+
"thetadatadx-darwin-arm64": "13.0.0",
|
|
37
|
+
"thetadatadx-linux-x64-gnu": "13.0.0",
|
|
38
|
+
"thetadatadx-win32-x64-msvc": "13.0.0"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">= 20"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"index.js",
|
|
45
|
+
"index.d.ts",
|
|
46
|
+
"streaming-session.js",
|
|
47
|
+
"streaming-session.d.ts",
|
|
48
|
+
"record_batch_forwarder.js"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Internal forwarder for `StreamView.prototype.batches`. Not part of the
|
|
4
|
+
// public API: `streaming-session.js` installs it onto the native prototype
|
|
5
|
+
// and the test suite imports it from here to drive the real
|
|
6
|
+
// options-object -> native call shape against a stub native method (no live
|
|
7
|
+
// server). `RecordBatchStream` is injected rather than required to keep this
|
|
8
|
+
// free of a circular dependency on `streaming-session.js`.
|
|
9
|
+
//
|
|
10
|
+
// The native `batches(options?)` takes ONE object argument; the wrap forwards
|
|
11
|
+
// the caller's single options object straight through (no positional
|
|
12
|
+
// explosion) and re-wraps the returned native handle in a `RecordBatchStream`.
|
|
13
|
+
function wrapStreamViewBatches(nativeBatches, RecordBatchStream) {
|
|
14
|
+
return async function batches(...args) {
|
|
15
|
+
const handle = await nativeBatches.apply(this, args);
|
|
16
|
+
return new RecordBatchStream(handle);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = { wrapStreamViewBatches };
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript surface for the `await using` streaming wrapper.
|
|
3
|
+
*
|
|
4
|
+
* `await using session = await client.streaming(callback)` (TC39 explicit
|
|
5
|
+
* resource management) registers the callback via `startStreaming`
|
|
6
|
+
* and pairs `stopStreaming()` + `awaitDrain(5000)` on dispose, mirroring
|
|
7
|
+
* the C++ RAII destructor in `thetadatadx-cpp/src/thetadatadx.cpp`.
|
|
8
|
+
*
|
|
9
|
+
* The runtime wrapper proxies every attribute access to the underlying
|
|
10
|
+
* `Client` (resolving the `client.stream` `StreamView` surface first),
|
|
11
|
+
* so the type surface here extends `Client` and `StreamView` -- adding a
|
|
12
|
+
* `subscribeX` method to either napi binding flows through to the
|
|
13
|
+
* session type with no drift.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/* eslint-disable */
|
|
17
|
+
|
|
18
|
+
import type { Client, MarketDataClient, StreamView, StreamEvent, ContractRef } from './index';
|
|
19
|
+
|
|
20
|
+
export * from './index';
|
|
21
|
+
|
|
22
|
+
/** `Contract` aliases `ContractRef`. napi-rs exposes the fluent
|
|
23
|
+
* contract type under `ContractRef` because the `Contract` symbol is
|
|
24
|
+
* already taken by the streaming event-payload data class. The public
|
|
25
|
+
* surface documented in the quickstart and reference is
|
|
26
|
+
* `Contract.stock("AAPL")` / `Contract.option(...)`, so the alias
|
|
27
|
+
* keeps the type-side and runtime-side names identical. */
|
|
28
|
+
export const Contract: typeof ContractRef;
|
|
29
|
+
export type Contract = ContractRef;
|
|
30
|
+
|
|
31
|
+
// ── Typed error hierarchy ─────────────────────────────────────────────
|
|
32
|
+
//
|
|
33
|
+
// Every `thetadatadx::Error` surfaced through the napi boundary is
|
|
34
|
+
// re-cast on the JS side as one of the leaves below. The canonical leaf
|
|
35
|
+
// set (`NotFoundError`, `DeadlineExceededError`, `UnavailableError`,
|
|
36
|
+
// `InvalidParameterError`, ...) is identical to the Python, C++, and C
|
|
37
|
+
// ABI leaf sets, so a `catch` clause ports across bindings by class name
|
|
38
|
+
// — port a Python `except thetadatadx.SubscriptionError` clause to TS by
|
|
39
|
+
// writing `catch (e) { if (e instanceof thetadatadx.SubscriptionError) { ... } }`.
|
|
40
|
+
// Python additionally ships two back-compat aliases
|
|
41
|
+
// (`NoDataFoundError` / `TimeoutError`) that have no equivalent here.
|
|
42
|
+
|
|
43
|
+
/** Base class for every typed error this binding throws. */
|
|
44
|
+
export class ThetaDataError extends Error {}
|
|
45
|
+
/** Authentication failed against ThetaData Nexus. */
|
|
46
|
+
export class AuthenticationError extends ThetaDataError {}
|
|
47
|
+
/** Supplied credentials were rejected. */
|
|
48
|
+
export class InvalidCredentialsError extends AuthenticationError {}
|
|
49
|
+
/** Tier / plan does not cover the request (gRPC `PermissionDenied`). */
|
|
50
|
+
export class SubscriptionError extends ThetaDataError {}
|
|
51
|
+
/** Rate limit / quota exhausted (gRPC `ResourceExhausted`, HTTP 429). */
|
|
52
|
+
export class RateLimitError extends ThetaDataError {
|
|
53
|
+
/**
|
|
54
|
+
* Server-supplied minimum back-off in seconds, parsed from the
|
|
55
|
+
* upstream `google.rpc.RetryInfo` hint, or `null` when none was
|
|
56
|
+
* supplied. Always present so callers can read it unconditionally.
|
|
57
|
+
*/
|
|
58
|
+
retryAfter: number | null;
|
|
59
|
+
}
|
|
60
|
+
/** A client-side parameter was rejected by input validation. */
|
|
61
|
+
export class InvalidParameterError extends ThetaDataError {}
|
|
62
|
+
/** Empty result / unknown contract (gRPC `NotFound`). */
|
|
63
|
+
export class NotFoundError extends ThetaDataError {}
|
|
64
|
+
/** Per-request deadline elapsed (gRPC `DeadlineExceeded`). */
|
|
65
|
+
export class DeadlineExceededError extends ThetaDataError {}
|
|
66
|
+
/** Upstream unavailable (gRPC `Unavailable`, often retryable). */
|
|
67
|
+
export class UnavailableError extends ThetaDataError {}
|
|
68
|
+
/** Transport-layer failure (TCP / TLS / IO) other than `Unavailable`. */
|
|
69
|
+
export class NetworkError extends ThetaDataError {}
|
|
70
|
+
/** Decoder schema mismatch — usually a server proto bump. */
|
|
71
|
+
export class SchemaMismatchError extends ThetaDataError {}
|
|
72
|
+
/** Streaming protocol / state-machine failure. */
|
|
73
|
+
export class StreamError extends ThetaDataError {}
|
|
74
|
+
/** Configuration fault (config-file I/O, TOML parse). */
|
|
75
|
+
export class ConfigError extends ThetaDataError {}
|
|
76
|
+
|
|
77
|
+
/** Callback signature mirrored from the napi-generated
|
|
78
|
+
* `startStreaming(callback)` declaration in `index.d.ts`. */
|
|
79
|
+
export type StreamEventCallback = (event: StreamEvent) => void;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Context object returned by `client.streaming(callback)`. Implements
|
|
83
|
+
* `Symbol.asyncDispose` so `await using session = ...` blocks pair
|
|
84
|
+
* `startStreaming` (on the awaited factory call) with
|
|
85
|
+
* `stopStreaming() + awaitDrain(5000)` on scope exit. The ring-drain
|
|
86
|
+
* barrier guarantees the consumer thread has stopped and enqueues no
|
|
87
|
+
* further events before the JS closure is released. It is not an exact
|
|
88
|
+
* "no callback after dispose" barrier on the napi delivery path:
|
|
89
|
+
* already-queued events can still invoke the callback on later
|
|
90
|
+
* event-loop turns after the disposer resolves (unlike Python/C++, whose
|
|
91
|
+
* callback runs on the consumer thread). Do not free callback-referenced
|
|
92
|
+
* state at scope exit assuming zero further invocations.
|
|
93
|
+
*
|
|
94
|
+
* The runtime forwarding is `Proxy`-based and resolves names against
|
|
95
|
+
* `client.stream` (the `StreamView` streaming surface) first, then the
|
|
96
|
+
* `Client` itself. The type surface mirrors that by extending both
|
|
97
|
+
* `Client` and `StreamView`, so `session.subscribe(...)`,
|
|
98
|
+
* `session.reconnect()`, and `session.activeSubscriptions()` type-check
|
|
99
|
+
* alongside every `Client` method with zero hand-listed mirror.
|
|
100
|
+
*/
|
|
101
|
+
export interface StreamingSession extends Client, StreamView {
|
|
102
|
+
/**
|
|
103
|
+
* Invoked by `await using session = ...` on scope exit. Stops the
|
|
104
|
+
* streaming connection and awaits the ring-drain barrier so the consumer
|
|
105
|
+
* thread has stopped and enqueues no further events before the JS closure
|
|
106
|
+
* is released. Already-queued events may still invoke the callback on
|
|
107
|
+
* later event-loop turns after this resolves (see the interface doc).
|
|
108
|
+
* Drain timeouts emit `console.warn` rather than throwing.
|
|
109
|
+
*/
|
|
110
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export declare const StreamingSession: {
|
|
114
|
+
new (client: Client): StreamingSession;
|
|
115
|
+
prototype: StreamingSession;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
declare module './index' {
|
|
119
|
+
interface Client {
|
|
120
|
+
/**
|
|
121
|
+
* Open a context-managed streaming session.
|
|
122
|
+
*
|
|
123
|
+
* `await using session = await client.streaming(callback)` registers
|
|
124
|
+
* `callback` via `startStreaming` and pairs `stopStreaming()` +
|
|
125
|
+
* `awaitDrain(5000)` on scope exit, mirroring the C++ RAII
|
|
126
|
+
* destructor in `thetadatadx-cpp/src/thetadatadx.cpp`. If the drain barrier
|
|
127
|
+
* times out, `console.warn` fires but the `using` scope exits
|
|
128
|
+
* normally so any error from the body is not masked.
|
|
129
|
+
*/
|
|
130
|
+
streaming(callback: StreamEventCallback): Promise<StreamingSession>;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* TC39 explicit resource management: `using client = connect(...)` calls
|
|
134
|
+
* this on synchronous scope exit. Runs {@link Client.close} — stops
|
|
135
|
+
* streaming if live and releases the callback. For a streaming-drain
|
|
136
|
+
* barrier before release, use `await using` ({@link Client[Symbol.asyncDispose]})
|
|
137
|
+
* or the context-managed session.
|
|
138
|
+
*/
|
|
139
|
+
[Symbol.dispose](): void;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* TC39 explicit resource management: `await using client = ...` calls this
|
|
143
|
+
* on scope exit. Stops streaming and awaits the ring-drain barrier so the
|
|
144
|
+
* consumer thread has stopped and enqueues no further events before the JS
|
|
145
|
+
* closure is released. Already-queued events may still invoke the callback
|
|
146
|
+
* on later event-loop turns after this resolves (napi delivery is
|
|
147
|
+
* downstream of the consumer thread, unlike Python/C++). Drain timeouts
|
|
148
|
+
* emit `console.warn` rather than throwing, so an error from the `using`
|
|
149
|
+
* body is not masked.
|
|
150
|
+
*/
|
|
151
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
interface MarketDataClient {
|
|
155
|
+
/**
|
|
156
|
+
* TC39 explicit resource management: `using client = await
|
|
157
|
+
* MarketDataClient.connect(...)` calls this on scope exit. Runs
|
|
158
|
+
* {@link MarketDataClient.close}. The market-data-only surface has no
|
|
159
|
+
* streaming to drain, so the sync and async disposers are equivalent.
|
|
160
|
+
*/
|
|
161
|
+
[Symbol.dispose](): void;
|
|
162
|
+
|
|
163
|
+
/** Async counterpart of {@link MarketDataClient[Symbol.dispose]}; no
|
|
164
|
+
* streaming drain on the market-data-only surface. */
|
|
165
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
interface StreamingClient {
|
|
169
|
+
/**
|
|
170
|
+
* Open a context-managed streaming session over this standalone client:
|
|
171
|
+
* `await using session = await streamingClient.streaming(callback)`
|
|
172
|
+
* registers `callback` via `startStreaming` and pairs `stopStreaming()` +
|
|
173
|
+
* `awaitDrain(5000)` on scope exit, the same RAII semantics as the unified
|
|
174
|
+
* {@link Client.streaming} helper.
|
|
175
|
+
*/
|
|
176
|
+
streaming(callback: StreamEventCallback): Promise<StreamingSession>;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* TC39 explicit resource management: `using sc = StreamingClient.connect(...)`
|
|
180
|
+
* calls this on synchronous scope exit. Runs `stopStreaming()` — the
|
|
181
|
+
* standalone client's terminal teardown (it has no separate `close()`).
|
|
182
|
+
* For a streaming-drain barrier before release, use `await using`
|
|
183
|
+
* ({@link StreamingClient[Symbol.asyncDispose]}) or the session.
|
|
184
|
+
*/
|
|
185
|
+
[Symbol.dispose](): void;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* TC39 explicit resource management: `await using sc = ...` calls this on
|
|
189
|
+
* scope exit. Stops streaming and awaits the ring-drain barrier so the
|
|
190
|
+
* consumer thread has stopped and enqueues no further events before the JS
|
|
191
|
+
* closure is released. Already-queued events may still invoke the callback
|
|
192
|
+
* on later event-loop turns after this resolves (see {@link Client}'s async
|
|
193
|
+
* disposer). Drain timeouts emit `console.warn` rather than throwing.
|
|
194
|
+
*/
|
|
195
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
interface StreamView {
|
|
199
|
+
/**
|
|
200
|
+
* Open a pull-based columnar reader over the live stream — a sibling
|
|
201
|
+
* to the per-event `startStreaming(callback)`.
|
|
202
|
+
*
|
|
203
|
+
* The same subscriptions feed it, but market-data events arrive as
|
|
204
|
+
* apache-arrow `RecordBatch` values under a fixed schema, consumed
|
|
205
|
+
* with `for await (const batch of reader)`. The reader closes
|
|
206
|
+
* (unsubscribe + tear down) on `close()` or `Symbol.asyncDispose`
|
|
207
|
+
* (`await using reader = await client.stream.batches()`). Subscribe on
|
|
208
|
+
* this same surface first, then open the reader.
|
|
209
|
+
*
|
|
210
|
+
* The runtime returns the JS {@link RecordBatchStream} wrapper around
|
|
211
|
+
* the native handle; this override replaces the napi-generated
|
|
212
|
+
* `Promise<RecordBatchStreamHandle>` return type.
|
|
213
|
+
*/
|
|
214
|
+
batches(options?: BatchesOptions): Promise<RecordBatchStream>;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Optional tuning for {@link StreamView.batches}. */
|
|
219
|
+
export interface BatchesOptions {
|
|
220
|
+
/** Rows per batch. Default 65536. A batch also flushes on {@link lingerMs}. */
|
|
221
|
+
batchSize?: number;
|
|
222
|
+
/**
|
|
223
|
+
* Milliseconds a partial batch waits before flushing, so a quiet stream
|
|
224
|
+
* still delivers. Default 50.
|
|
225
|
+
*/
|
|
226
|
+
lingerMs?: number;
|
|
227
|
+
/**
|
|
228
|
+
* Backpressure when the reader falls behind: `"block"` (default,
|
|
229
|
+
* lossless — applies backpressure to the wire) or `"dropOldest"`
|
|
230
|
+
* (bounded buffer; drops the oldest batch and counts it in
|
|
231
|
+
* {@link RecordBatchStream.dropped}).
|
|
232
|
+
*/
|
|
233
|
+
backpressure?: 'block' | 'dropOldest';
|
|
234
|
+
/** Bounded-buffer depth in batches for `"dropOldest"`. Default 4. */
|
|
235
|
+
capacity?: number;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Pull-based columnar reader returned by `client.stream.batches(...)`.
|
|
240
|
+
*
|
|
241
|
+
* `AsyncIterable` of apache-arrow `RecordBatch` values under a fixed
|
|
242
|
+
* schema, and a TC39 async-disposable: `await using reader = ...` closes
|
|
243
|
+
* it on scope exit, or call {@link close}. Yields are concat-safe — every
|
|
244
|
+
* batch carries the identical {@link schema}.
|
|
245
|
+
*/
|
|
246
|
+
export interface RecordBatchStream extends AsyncIterable<import('apache-arrow').RecordBatch> {
|
|
247
|
+
/** The fixed Arrow schema every yielded batch carries. */
|
|
248
|
+
readonly schema: import('apache-arrow').Schema;
|
|
249
|
+
/** Batches dropped so far under `"dropOldest"`; `0` under `"block"`. */
|
|
250
|
+
readonly dropped: number;
|
|
251
|
+
/** Close the reader: unsubscribe and tear the streaming session down. Idempotent. */
|
|
252
|
+
close(): void;
|
|
253
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Value binding for the {@link RecordBatchStream} class, exported at runtime
|
|
258
|
+
* so consumers can reference it (for example `stream instanceof
|
|
259
|
+
* RecordBatchStream`). The reader is produced by {@link StreamView.batches},
|
|
260
|
+
* not constructed directly, so the constructor is not part of the public
|
|
261
|
+
* surface. Mirrors the paired {@link StreamingSession} value declaration.
|
|
262
|
+
*/
|
|
263
|
+
export declare const RecordBatchStream: {
|
|
264
|
+
prototype: RecordBatchStream;
|
|
265
|
+
new (...args: never[]): RecordBatchStream;
|
|
266
|
+
};
|