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/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
+ };