diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..8260426 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,83 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is the QuestDB Node.js client library (@questdb/nodejs-client) that provides data ingestion capabilities to QuestDB databases. The client supports multiple transport protocols (HTTP/HTTPS, TCP/TCPS) and authentication methods. + +## Development Commands + +### Build +```bash +pnpm build # Build the library using bunchee (produces both ESM and CJS outputs) +``` + +### Testing +```bash +pnpm test # Run all tests using Vitest +``` + +### Code Quality +```bash +pnpm eslint # Run ESLint on all source files +pnpm typecheck # Run TypeScript type checking without emitting files +pnpm format # Format code using Prettier +``` + +### Documentation +```bash +pnpm docs # Build JSDoc documentation +pnpm preview:docs # Preview generated documentation locally +``` + +## Architecture + +### Core Components + +1. **Sender** (`src/sender.ts`): Main API class that orchestrates data ingestion. Handles auto-flushing, connection management, and provides the builder pattern API for constructing rows. + +2. **Transport Layer** (`src/transport/`): + - `http/undici.ts`: Default HTTP transport using Undici library for high performance + - `http/stdlib.ts`: Alternative HTTP transport using Node.js built-in modules + - `tcp.ts`: TCP/TCPS transport for persistent connections with JWK authentication + - Protocol negotiation and retry logic for HTTP transports + +3. **Buffer System** (`src/buffer/`): + - `bufferv1.ts`: Text-based protocol (version 1) for backward compatibility + - `bufferv2.ts`: Binary protocol (version 2) with double encoding and array support + - Dynamic buffer resizing and row-level transaction support + +4. **Configuration** (`src/options.ts`): Comprehensive options parsing from connection strings with validation and deprecation handling. + +### Protocol Versions + +- **Version 1**: Text-based serialization, compatible with older QuestDB versions +- **Version 2**: Binary encoding for doubles, supports array columns, better performance +- **Auto-negotiation**: HTTP transport can automatically detect and use the best protocol version + +### Key Design Patterns + +- Builder pattern for row construction with method chaining +- Factory methods (`Sender.fromConfig()`, `Sender.fromEnv()`) for validated initialization +- Abstract base classes for transport and buffer implementations +- Automatic buffer management with configurable auto-flush behavior + +## Testing Strategy + +Tests are organized by component: +- `sender.config.test.ts`: Configuration parsing and validation +- `sender.buffer.test.ts`: Buffer operations and protocol serialization +- `sender.transport.test.ts`: Transport layer functionality +- `sender.integration.test.ts`: End-to-end integration tests with QuestDB + +Integration tests use TestContainers to spin up QuestDB instances for realistic testing. + +## Important Implementation Notes + +- The client requires Node.js v20+ for Undici support +- Authentication is handled differently per transport (Basic/Bearer for HTTP, JWK for TCP) +- Buffer automatically resizes up to `max_buf_size` (default 100MB) +- Auto-flush triggers based on row count or time interval +- Each worker thread needs its own Sender instance (buffers cannot be shared) +- Protocol version 2 is recommended for new implementations with array column support \ No newline at end of file diff --git a/README.md b/README.md index ff2d719..7e6fb85 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,3 @@ -# QuestDB Node.js Client - -## Requirements - -The client requires Node.js v20 or newer version. - ## Installation ```shell @@ -19,73 +13,53 @@ pnpm add @questdb/nodejs-client ## Compatibility table -| QuestDB client version | Node.js version | HTTP Agent | -|------------------------| --------------- |--------------| -| ^4.0.0 | >=v20.X.X | Undici Agent | -| ^3.0.0 | stdlib_http option to switch to the standard HTTP/HTTPS modules. ## Configuration options Detailed description of the client's configuration options can be found in -the SenderOptions documentation. +the {@link SenderOptions} documentation. ## Examples The examples below demonstrate how to use the client.
-For more details, please, check the Sender's documentation. +For more details, please, check the {@link Sender}'s documentation. ### Basic API usage -```javascript +```typescript import { Sender } from "@questdb/nodejs-client"; async function run() { - // create a sender - const sender = await Sender.fromConfig('http::addr=localhost:9000'); - - // order book snapshots - const orderBooks = [ - { - symbol: 'BTC-USD', - exchange: 'COINBASE', - timestamp: Date.now(), - bidPrices: [50100.25, 50100.20, 50100.15, 50100.10, 50100.05], - bidSizes: [0.5, 1.2, 2.1, 0.8, 3.5], - askPrices: [50100.30, 50100.35, 50100.40, 50100.45, 50100.50], - askSizes: [0.6, 1.5, 1.8, 2.2, 4.0] - }, - { - symbol: 'ETH-USD', - exchange: 'COINBASE', - timestamp: Date.now(), - bidPrices: [2850.50, 2850.45, 2850.40, 2850.35, 2850.30], - bidSizes: [5.0, 8.2, 12.5, 6.8, 15.0], - askPrices: [2850.55, 2850.60, 2850.65, 2850.70, 2850.75], - askSizes: [4.5, 7.8, 10.2, 8.5, 20.0] - } - ]; - - try { - // add rows to the buffer of the sender - for (const orderBook of orderBooks) { - await sender - .table('order_book_l2') - .symbol('symbol', orderBook.symbol) - .symbol('exchange', orderBook.exchange) - .arrayColumn('bid_prices', orderBook.bidPrices) - .arrayColumn('bid_sizes', orderBook.bidSizes) - .arrayColumn('ask_prices', orderBook.askPrices) - .arrayColumn('ask_sizes', orderBook.askSizes) - .at(orderBook.timestamp, 'ms'); - } - - // flush the buffer of the sender, sending the data to QuestDB - // the buffer is cleared after the data is sent, and the sender is ready to accept new data - await sender.flush(); - } finally { - // close the connection after all rows ingested - await sender.close(); - } + // create a sender using HTTP protocol + const sender = await Sender.fromConfig("http::addr=127.0.0.1:9000"); + + // add rows to the buffer of the sender + await sender + .table("trades") + .symbol("symbol", "BTC-USD") + .symbol("side", "sell") + .floatColumn("price", 39269.98) + .floatColumn("amount", 0.011) + .at(Date.now(), "ms"); + + // flush the buffer of the sender, sending the data to QuestDB + // the buffer is cleared after the data is sent, and the sender is ready to accept new data + await sender.flush(); + + // close the connection after all rows ingested + // unflushed data will be lost + await sender.close(); } run().then(console.log).catch(console.error); @@ -93,18 +67,23 @@ run().then(console.log).catch(console.error); ### Authentication and secure connection -#### Username and password authentication +#### Username and password authentication with HTTP transport -```javascript +```typescript import { Sender } from "@questdb/nodejs-client"; async function run() { - // create a sender using HTTPS protocol with username and password authentication - const sender = Sender.fromConfig( - "https::addr=127.0.0.1:9000;username=admin;password=quest", + // authentication details + const USER = "admin"; + const PWD = "quest"; + + // pass the authentication details to the sender + // for secure connection use 'https' protocol instead of 'http' + const sender = await Sender.fromConfig( + `http::addr=127.0.0.1:9000;username=${USER};password=${PWD}` ); - // send the data over the authenticated and secure connection + // add rows to the buffer of the sender await sender .table("trades") .symbol("symbol", "ETH-USD") @@ -112,6 +91,8 @@ async function run() { .floatColumn("price", 2615.54) .floatColumn("amount", 0.00044) .at(Date.now(), "ms"); + + // flush the buffer of the sender, sending the data to QuestDB await sender.flush(); // close the connection after all rows ingested @@ -121,18 +102,22 @@ async function run() { run().catch(console.error); ``` -#### Token authentication +#### REST token authentication with HTTP transport ```typescript import { Sender } from "@questdb/nodejs-client"; -async function run(): Promise { - // create a sender using HTTPS protocol with bearer token authentication - const sender: Sender = Sender.fromConfig( - "https::addr=127.0.0.1:9000;token=Xyvd3er6GF87ysaHk", +async function run() { + // authentication details + const TOKEN = "Xyvd3er6GF87ysaHk"; + + // pass the authentication details to the sender + // for secure connection use 'https' protocol instead of 'http' + const sender = await Sender.fromConfig( + `http::addr=127.0.0.1:9000;token=${TOKEN}` ); - // send the data over the authenticated and secure connection + // add rows to the buffer of the sender await sender .table("trades") .symbol("symbol", "ETH-USD") @@ -140,6 +125,43 @@ async function run(): Promise { .floatColumn("price", 2615.54) .floatColumn("amount", 0.00044) .at(Date.now(), "ms"); + + // flush the buffer of the sender, sending the data to QuestDB + await sender.flush(); + + // close the connection after all rows ingested + await sender.close(); +} + +run().catch(console.error); +``` + +#### JWK token authentication with TCP transport + +```typescript +import { Sender } from "@questdb/nodejs-client"; + +async function run() { + // authentication details + const CLIENT_ID = "admin"; + const PRIVATE_KEY = "ZRxmCOQBpZoj2fZ-lEtqzVDkCre_ouF3ePpaQNDwoQk"; + + // pass the authentication details to the sender + const sender = await Sender.fromConfig( + `tcp::addr=127.0.0.1:9009;username=${CLIENT_ID};token=${PRIVATE_KEY}` + ); + await sender.connect(); + + // add rows to the buffer of the sender + await sender + .table("trades") + .symbol("symbol", "BTC-USD") + .symbol("side", "sell") + .floatColumn("price", 39269.98) + .floatColumn("amount", 0.001) + .at(Date.now(), "ms"); + + // flush the buffer of the sender, sending the data to QuestDB await sender.flush(); // close the connection after all rows ingested @@ -149,16 +171,68 @@ async function run(): Promise { run().catch(console.error); ``` +### Array usage example + +```typescript +import { Sender } from "@questdb/nodejs-client"; + +async function run() { + // create a sender + const sender = await Sender.fromConfig('http::addr=localhost:9000'); + + // order book snapshots to ingest + const orderBooks = [ + { + symbol: 'BTC-USD', + exchange: 'Coinbase', + timestamp: Date.now(), + bidPrices: [50100.25, 50100.20, 50100.15, 50100.10, 50100.05], + bidSizes: [0.5, 1.2, 2.1, 0.8, 3.5], + askPrices: [50100.30, 50100.35, 50100.40, 50100.45, 50100.50], + askSizes: [0.6, 1.5, 1.8, 2.2, 4.0] + }, + { + symbol: 'ETH-USD', + exchange: 'Coinbase', + timestamp: Date.now(), + bidPrices: [2850.50, 2850.45, 2850.40, 2850.35, 2850.30], + bidSizes: [5.0, 8.2, 12.5, 6.8, 15.0], + askPrices: [2850.55, 2850.60, 2850.65, 2850.70, 2850.75], + askSizes: [4.5, 7.8, 10.2, 8.5, 20.0] + } + ]; + + try { + // add rows to the buffer of the sender + for (const orderBook of orderBooks) { + await sender + .table('order_book_l2') + .symbol('symbol', orderBook.symbol) + .symbol('exchange', orderBook.exchange) + .arrayColumn('bid_prices', orderBook.bidPrices) + .arrayColumn('bid_sizes', orderBook.bidSizes) + .arrayColumn('ask_prices', orderBook.askPrices) + .arrayColumn('ask_sizes', orderBook.askSizes) + .at(orderBook.timestamp, 'ms'); + } + + // flush the buffer of the sender, sending the data to QuestDB + // the buffer is cleared after the data is sent, and the sender is ready to accept new data + await sender.flush(); + } finally { + // close the connection after all rows ingested + await sender.close(); + } +} + +run().then(console.log).catch(console.error); +``` + ### Worker threads example -```javascript +```typescript import { Sender } from "@questdb/nodejs-client"; -const { - Worker, - isMainThread, - parentPort, - workerData, -} = require("worker_threads"); +import { Worker, isMainThread, parentPort, workerData } from "worker_threads"; // fake venue // generates random prices and amounts for a ticker for max 5 seconds, then the feed closes @@ -188,7 +262,7 @@ async function run() { const tickers = ["ETH-USD", "BTC-USD", "SOL-USD", "DOGE-USD"]; // main thread to start a worker thread for each ticker for (let ticker of tickers) { - const worker = new Worker(__filename, { workerData: { ticker: ticker } }) + new Worker(__filename, { workerData: { ticker: ticker } }) .on("error", (err) => { throw err; }) @@ -202,7 +276,7 @@ async function run() { } else { // it is important that each worker has a dedicated sender object // threads cannot share the sender because they would write into the same buffer - const sender = Sender.fromConfig("http::addr=127.0.0.1:9000"); + const sender = await Sender.fromConfig("http::addr=127.0.0.1:9000"); // subscribe for the market data of the ticker assigned to the worker // ingest each price update into the database using the sender @@ -227,11 +301,11 @@ async function run() { } } -function sleep(ms) { +function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } -function rndInt(limit) { +function rndInt(limit: number) { return Math.floor(Math.random() * limit + 1); } diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e2ac661 --- /dev/null +++ b/docs/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/HttpTransport.html b/docs/HttpTransport.html deleted file mode 100644 index a40ec94..0000000 --- a/docs/HttpTransport.html +++ /dev/null @@ -1,445 +0,0 @@ - - - - - JSDoc: Class: HttpTransport - - - - - - - - - - -
- -

Class: HttpTransport

- - - - - - -
- -
- -

HttpTransport(options)

- -
HTTP transport implementation using Node.js built-in http/https modules.
-Supports both HTTP and HTTPS protocols with configurable authentication.
- - -
- -
-
- - - - -

Constructor

- - - -

new HttpTransport(options)

- - - - - - -
- Creates a new HttpTransport instance using Node.js HTTP modules. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - Sender configuration object containing connection details
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if the protocol is not 'http' or 'https' - -
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

send(data, retryBegin, retryInterval)

- - - - - - -
- Sends data to QuestDB using HTTP POST. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -Buffer - - - - Buffer containing the data to send
retryBegin - - -number - - - - Internal parameter for tracking retry start time
retryInterval - - -number - - - - Internal parameter for tracking retry intervals
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if request fails after all retries or times out - -
- - - - - -
Returns:
- - -
- Promise resolving to true if data was sent successfully -
- - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/HttpTransportBase.html b/docs/HttpTransportBase.html deleted file mode 100644 index e0e0464..0000000 --- a/docs/HttpTransportBase.html +++ /dev/null @@ -1,548 +0,0 @@ - - - - - JSDoc: Class: HttpTransportBase - - - - - - - - - - -
- -

Class: HttpTransportBase

- - - - - - -
- -
- -

HttpTransportBase(options)

- -
Abstract base class for HTTP-based transport implementations.
-Provides common configuration and functionality for HTTP and HTTPS protocols.
- - -
- -
-
- - - - -

Constructor

- - - -

new HttpTransportBase(options)

- - - - - - -
- Creates a new HttpTransportBase instance. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - Sender configuration options including connection and authentication details
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if required protocol or host options are missing - -
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async) close()

- - - - - - -
- HTTP transport does not require explicit connection closure. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Promise that resolves immediately -
- - - - - - - - - - - - - - - -

connect()

- - - - - - -
- HTTP transport does not require explicit connection establishment. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error indicating connect is not required for HTTP transport - -
- - - - - - - - - - - - - - - - -

getDefaultAutoFlushRows() → {number}

- - - - - - -
- Gets the default auto-flush row count for HTTP transport. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Default number of rows that trigger auto-flush -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/Sender.html b/docs/Sender.html deleted file mode 100644 index 09ab939..0000000 --- a/docs/Sender.html +++ /dev/null @@ -1,2891 +0,0 @@ - - - - - JSDoc: Class: Sender - - - - - - - - - - -
- -

Class: Sender

- - - - - - -
- -
- -

Sender(options)

- -
The QuestDB client's API provides methods to connect to the database, ingest data, and close the connection.
-The client supports multiple transport protocols. -

-Transport Options: -

    -
  • HTTP: Uses standard HTTP requests for data ingestion. Provides immediate feedback via HTTP response codes. -Recommended for most use cases due to superior error handling and debugging capabilities. Uses Undici library by default for high performance.
  • -
  • HTTPS: Secure HTTP transport with TLS encryption. Same benefits as HTTP but with encrypted communication. -Supports certificate validation and custom CA certificates.
  • -
  • TCP: Direct TCP connection, provides persistent connections. Uses JWK token-based authentication.
  • -
  • TCPS: Secure TCP transport with TLS encryption.
  • -
-

-

-The client supports authentication.
-Authentication details can be passed to the Sender in its configuration options.
-The client supports Basic username/password and Bearer token authentication methods when used with HTTP protocol, -and JWK token authentication when ingesting data via TCP.
-Please, note that authentication is enabled by default in QuestDB Enterprise only.
-Details on how to configure authentication in the open source version of -QuestDB: https://questdb.io/docs/reference/api/ilp/authenticate -

-

-The client also supports TLS encryption for both, HTTP and TCP transports to provide a secure connection.
-Please, note that the open source version of QuestDB does not support TLS, and requires an external reverse-proxy, -such as Nginx to enable encryption. -

-

-The client supports multiple protocol versions for data serialization. Protocol version 1 uses text-based -serialization, while version 2 uses binary encoding for doubles and supports array columns for improved -performance. The client can automatically negotiate the protocol version with the server when using HTTP/HTTPS -by setting the protocol_version to 'auto' (default behavior). -

-

-The client uses a buffer to store data. It automatically flushes the buffer by sending its content to the server. -Auto flushing can be disabled via configuration options to gain control over transactions. Initial and maximum -buffer sizes can also be set. -

-

-It is recommended that the Sender is created by using one of the static factory methods, -Sender.fromConfig(configString, extraOptions) or Sender.fromEnv(extraOptions). -If the Sender is created via its constructor, at least the SenderOptions configuration object should be -initialized from a configuration string to make sure that the parameters are validated.
-Detailed description of the Sender's configuration options can be found in -the SenderOptions documentation. -

-

-Transport Configuration Examples: -

    -
  • HTTP: Sender.fromConfig("http::addr=localhost:9000")
  • -
  • HTTPS with authentication: Sender.fromConfig("https::addr=localhost:9000;username=admin;password=secret")
  • -
  • TCP: Sender.fromConfig("tcp::addr=localhost:9009")
  • -
  • TCPS with authentication: Sender.fromConfig("tcps::addr=localhost:9009;username=user;token=private_key")
  • -
-

-

-HTTP Transport Implementation:
-By default, HTTP/HTTPS transport uses the high-performance Undici library for connection management and request handling. -For compatibility or specific requirements, you can enable the standard HTTP transport using Node.js built-in modules -by setting stdlib_http=on in the configuration string. The standard HTTP transport provides the same functionality -but uses Node.js http/https modules instead of Undici. -

-

-Extra options can be provided to the Sender in the extraOptions configuration object.
-A custom logging function and a custom HTTP(S) agent can be passed to the Sender in this object.
-The logger implementation provides the option to direct log messages to the same place where the host application's -log is saved. The default logger writes to the console.
-The custom HTTP(S) agent option becomes handy if there is a need to modify the default options set for the -HTTP(S) connections. A popular setting would be disabling persistent connections, in this case an agent can be -passed to the Sender with keepAlive set to false.
-For example: Sender.fromConfig(`http::addr=host:port`, { agent: new undici.Agent({ connect: { keepAlive: false } })})
-If no custom agent is configured, the Sender will use its own agent which overrides some default values -of undici.Agent. The Sender's own agent uses persistent connections with 1 minute idle timeout, pipelines requests default to 1. -

- - -
- -
-
- - - - -

Constructor

- - - -

new Sender(options)

- - - - - - -
- Creates an instance of Sender. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - Sender configuration object.
-See SenderOptions documentation for detailed description of configuration options.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

arrayColumn(name, value) → {Sender}

- - - - - - -
- Writes an array column with its values into the buffer of the sender. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name
value - - -Array.<unknown> - - - - Array values to write (currently supports double arrays)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if arrays are not supported by the buffer implementation, or array validation fails: -- value is not an array -- or the shape of the array is irregular: the length of sub-arrays are different -- or the array is not homogeneous: its elements are not all the same type - -
- - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

(async) at(timestamp, unitopt)

- - - - - - -
- Closes the row after writing the designated timestamp into the buffer of the sender. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
timestamp - - -number -| - -bigint - - - - - - - - - - - - Designated epoch timestamp, accepts numbers or BigInts.
unit - - -string - - - - - - <optional>
- - - - - -
- - us - - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) atNow()

- - - - - - -
- Closes the row without writing designated timestamp into the buffer of the sender.
-Designated timestamp will be populated by the server on this record. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

booleanColumn(name, value) → {Sender}

- - - - - - -
- Writes a boolean column with its value into the buffer of the sender.
-Use it to insert into BOOLEAN columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name.
value - - -boolean - - - - Column value, accepts only boolean values.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

(async) close()

- - - - - - -
- Closes the connection to the database.
-Data sitting in the Sender's buffer will be lost unless flush() is called before close(). -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

connect() → {Promise.<boolean>}

- - - - - - -
- Creates a TCP connection to the database. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Resolves to true if the client is connected. -
- - - -
-
- Type -
-
- -Promise.<boolean> - - -
-
- - - - - - - - - - - - - -

floatColumn(name, value) → {Sender}

- - - - - - -
- Writes a 64-bit floating point value into the buffer of the sender.
-Use it to insert into DOUBLE or FLOAT database columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name.
value - - -number - - - - Column value, accepts only number values.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

(async) flush() → {Promise.<boolean>}

- - - - - - -
- Sends the content of the sender's buffer to the database and compacts the buffer. -If the last row is not finished it stays in the sender's buffer. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Resolves to true when there was data in the buffer to send, and it was sent successfully. -
- - - -
-
- Type -
-
- -Promise.<boolean> - - -
-
- - - - - - - - - - - - - -

intColumn(name, value) → {Sender}

- - - - - - -
- Writes a 64-bit signed integer into the buffer of the sender.
-Use it to insert into LONG, INT, SHORT and BYTE columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name.
value - - -number - - - - Column value, accepts only number values.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if the value is not an integer - -
- - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

reset() → {Sender}

- - - - - - -
- Resets the sender's buffer, data sitting in the buffer will be lost.
-In other words it clears the buffer, and sets the writing position to the beginning of the buffer. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

stringColumn(name, value) → {Sender}

- - - - - - -
- Writes a string column with its value into the buffer of the sender.
-Use it to insert into VARCHAR and STRING columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name.
value - - -string - - - - Column value, accepts only string values.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

symbol(name, value) → {Sender}

- - - - - - -
- Writes a symbol name and value into the buffer of the sender.
-Use it to insert into SYMBOL columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Symbol name.
value - - -unknown - - - - Symbol value, toString() is called to extract the actual symbol value from the parameter.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

table(table) → {Sender}

- - - - - - -
- Writes the table name into the buffer of the sender of the sender. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
table - - -string - - - - Table name.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

timestampColumn(name, value, unitopt) → {Sender}

- - - - - - -
- Writes a timestamp column with its value into the buffer of the sender.
-Use it to insert into TIMESTAMP columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
name - - -string - - - - - - - - - - - - Column name.
value - - -number -| - -bigint - - - - - - - - - - - - Epoch timestamp, accepts numbers or BigInts.
unit - - -string - - - - - - <optional>
- - - - - -
- - us - - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

(async, static) fromConfig(configurationString, extraOptions) → {Sender}

- - - - - - -
- Creates a Sender object by parsing the provided configuration string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
configurationString - - -string - - - - Configuration string.
extraOptions - - -object - - - - Optional extra configuration.
-- 'log' is a logging function used by the Sender.
-Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
-- 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
-Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- A Sender object initialized from the provided configuration string. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

(async, static) fromEnv(extraOptions) → {Sender}

- - - - - - -
- Creates a Sender object by parsing the configuration string set in the QDB_CLIENT_CONF environment variable. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
extraOptions - - -object - - - - Optional extra configuration.
-- 'log' is a logging function used by the Sender.
-Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
-- 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
-Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- A Sender object initialized from the QDB_CLIENT_CONF environment variable. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/SenderBufferBase.html b/docs/SenderBufferBase.html deleted file mode 100644 index 8b6d627..0000000 --- a/docs/SenderBufferBase.html +++ /dev/null @@ -1,2247 +0,0 @@ - - - - - JSDoc: Class: SenderBufferBase - - - - - - - - - - -
- -

Class: SenderBufferBase

- - - - - - -
- -
- -

SenderBufferBase(options)

- -
Abstract base class for SenderBuffer implementations.
-Provides common functionality for writing data into the buffer.
- - -
- -
-
- - - - -

Constructor

- - - -

new SenderBufferBase(options)

- - - - - - -
- Creates an instance of SenderBufferBase. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - Sender configuration object.
-See SenderOptions documentation for detailed description of configuration options.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

at(timestamp, unitopt)

- - - - - - -
- Closes the row after writing the designated timestamp into the buffer. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
timestamp - - -number -| - -bigint - - - - - - - - - - - - Designated epoch timestamp, accepts numbers or BigInts.
unit - - -string - - - - - - <optional>
- - - - - -
- - us - - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

atNow()

- - - - - - -
- Closes the row without writing designated timestamp into the buffer.
-Designated timestamp will be populated by the server on this record. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

booleanColumn(name, value) → {SenderBuffer}

- - - - - - -
- Writes a boolean column with its value into the buffer.
-Use it to insert into BOOLEAN columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name.
value - - -boolean - - - - Column value, accepts only boolean values.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this buffer. -
- - - -
-
- Type -
-
- -SenderBuffer - - -
-
- - - - - - - - - - - - - -

checkCapacity(data, base)

- - - - - - -
- Checks if the buffer has sufficient capacity for additional data and resizes if needed. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
data - - - - Array of strings to calculate the required capacity for
base - - - - 0 - - Base number of bytes to add to the calculation
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

currentPosition()

- - - - - - -
- Returns the current position of the buffer.
-New data will be written into the buffer starting from this position. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

intColumn(name, value) → {SenderBuffer}

- - - - - - -
- Writes a 64-bit signed integer into the buffer.
-Use it to insert into LONG, INT, SHORT and BYTE columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name.
value - - -number - - - - Column value, accepts only number values.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if the value is not an integer - -
- - - - - -
Returns:
- - -
- Returns with a reference to this buffer. -
- - - -
-
- Type -
-
- -SenderBuffer - - -
-
- - - - - - - - - - - - - -

reset() → {SenderBuffer}

- - - - - - -
- Resets the buffer, data sitting in the buffer will be lost.
-In other words it clears the buffer, and sets the writing position to the beginning of the buffer. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this buffer. -
- - - -
-
- Type -
-
- -SenderBuffer - - -
-
- - - - - - - - - - - - - -

stringColumn(name, value) → {SenderBuffer}

- - - - - - -
- Writes a string column with its value into the buffer.
-Use it to insert into VARCHAR and STRING columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name.
value - - -string - - - - Column value, accepts only string values.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this buffer. -
- - - -
-
- Type -
-
- -SenderBuffer - - -
-
- - - - - - - - - - - - - -

symbol(name, value) → {SenderBuffer}

- - - - - - -
- Writes a symbol name and value into the buffer.
-Use it to insert into SYMBOL columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Symbol name.
value - - -unknown - - - - Symbol value, toString() is called to extract the actual symbol value from the parameter.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this buffer. -
- - - -
-
- Type -
-
- -SenderBuffer - - -
-
- - - - - - - - - - - - - -

table(table) → {SenderBuffer}

- - - - - - -
- Writes the table name into the buffer. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
table - - -string - - - - Table name.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this buffer. -
- - - -
-
- Type -
-
- -SenderBuffer - - -
-
- - - - - - - - - - - - - -

timestampColumn(name, value, unitopt) → {SenderBuffer}

- - - - - - -
- Writes a timestamp column with its value into the buffer.
-Use it to insert into TIMESTAMP columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
name - - -string - - - - - - - - - - - - Column name.
value - - -number -| - -bigint - - - - - - - - - - - - Epoch timestamp, accepts numbers or BigInts.
unit - - -string - - - - - - <optional>
- - - - - -
- - us - - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this buffer. -
- - - -
-
- Type -
-
- -SenderBuffer - - -
-
- - - - - - - - - - - - - -

toBufferNew() → {Buffer}

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns a cropped buffer ready to send to the server, or null if there is nothing to send.
-The returned buffer is a copy of this buffer. -It also compacts the buffer. -
- - - -
-
- Type -
-
- -Buffer - - -
-
- - - - - - - - - - - - - -

toBufferView() → {Buffer}

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns a cropped buffer, or null if there is nothing to send.
-The returned buffer is backed by this buffer instance, meaning the view can change as the buffer is mutated. -Used only in tests to assert the buffer's content. -
- - - -
-
- Type -
-
- -Buffer - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/SenderBufferV1.html b/docs/SenderBufferV1.html deleted file mode 100644 index db324f9..0000000 --- a/docs/SenderBufferV1.html +++ /dev/null @@ -1,512 +0,0 @@ - - - - - JSDoc: Class: SenderBufferV1 - - - - - - - - - - -
- -

Class: SenderBufferV1

- - - - - - -
- -
- -

SenderBufferV1(options)

- -
Buffer implementation for protocol version 1. -Sends floating point numbers in their text form.
- - -
- -
-
- - - - -

Constructor

- - - -

new SenderBufferV1(options)

- - - - - - -
- Creates a new SenderBufferV1 instance. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - Sender configuration object.
-See SenderOptions documentation for detailed description of configuration options.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

arrayColumn()

- - - - - - -
- Array columns are not supported in protocol v1. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error indicating arrays are not supported in v1 - -
- - - - - - - - - - - - - - - - -

floatColumn(name, value) → {Sender}

- - - - - - -
- Writes a 64-bit floating point value into the buffer using v1 serialization (text format).
-Use it to insert into DOUBLE or FLOAT database columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name.
value - - -number - - - - Column value, accepts only number values.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this sender. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/SenderBufferV2.html b/docs/SenderBufferV2.html deleted file mode 100644 index 796eed0..0000000 --- a/docs/SenderBufferV2.html +++ /dev/null @@ -1,609 +0,0 @@ - - - - - JSDoc: Class: SenderBufferV2 - - - - - - - - - - -
- -

Class: SenderBufferV2

- - - - - - -
- -
- -

SenderBufferV2(options)

- -
Buffer implementation for protocol version 2. -Sends floating point numbers in binary form.
- - -
- -
-
- - - - -

Constructor

- - - -

new SenderBufferV2(options)

- - - - - - -
- Creates a new SenderBufferV2 instance. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - Sender configuration object.
-See SenderOptions documentation for detailed description of configuration options.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

arrayColumn(name, value) → {Sender}

- - - - - - -
- Write an array column with its values into the buffer using v2 format. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name
value - - -Array.<unknown> - - - - Array values to write (currently supports double arrays)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if array validation fails: -- value is not an array -- or the shape of the array is irregular: the length of sub-arrays are different -- or the array is not homogeneous: its elements are not all the same type - -
- - - - - -
Returns:
- - -
- Returns with a reference to this buffer. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -

floatColumn(name, value) → {Sender}

- - - - - - -
- Writes a 64-bit floating point value into the buffer using v2 serialization (binary format).
-Use it to insert into DOUBLE or FLOAT database columns. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - Column name.
value - - -number - - - - Column value, accepts only number values.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Returns with a reference to this buffer. -
- - - -
-
- Type -
-
- -Sender - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/SenderOptions.html b/docs/SenderOptions.html deleted file mode 100644 index db5500e..0000000 --- a/docs/SenderOptions.html +++ /dev/null @@ -1,843 +0,0 @@ - - - - - JSDoc: Class: SenderOptions - - - - - - - - - - -
- -

Class: SenderOptions

- - - - - - -
- -
- -

SenderOptions(configurationString, extraOptions)

- -
Sender configuration options.
-
-Properties of the object are initialized through a configuration string.
-The configuration string has the following format: <protocol>::<key>=<value><key>=<value>...;
-The keys are case-sensitive, the trailing semicolon is optional.
-The values are validated and an error is thrown if the format is invalid.
-
-Connection and protocol options -
    -
  • protocol: enum, accepted values: http, https, tcp, tcps - The protocol used to communicate with the server.
    -When https or tcps used, the connection is secured with TLS encryption. -
  • -
  • protocol_version: enum, accepted values: auto, 1, 2 - The protocol version used for data serialization.
    -Version 1 uses text-based serialization for all data types. Version 2 uses binary encoding for doubles and arrays.
    -When set to 'auto' (default for HTTP/HTTPS), the client automatically negotiates the highest supported version with the server.
    -TCP/TCPS connections default to version 1. -
  • -
  • addr: string - Hostname and port, separated by colon. This key is mandatory, but the port part is optional.
    -If no port is specified, a default will be used.
    -When the protocol is HTTP/HTTPS, the port defaults to 9000. When the protocol is TCP/TCPS, the port defaults to 9009.
    -
    -Examples: http::addr=localhost:9000, https::addr=localhost:9000, http::addr=localhost, tcp::addr=localhost:9009 -
  • -
-
-Authentication options -
    -
  • username: string - Used for authentication.
    -For HTTP, Basic Authentication requires the password option.
    -For TCP with JWK token authentication, token option is required. -
  • -
  • password: string - Password for HTTP Basic authentication, should be accompanied by the username option. -
  • -
  • token: string - For HTTP with Bearer authentication, this is the bearer token.
    -For TCP with JWK token authentication, this is the private key part of the JWK token, -and must be accompanied by the username option. -
  • -
-
-TLS options -
    -
  • tls_verify: enum, accepted values: on, unsafe_off - When the HTTPS or TCPS protocols are selected, TLS encryption is used.
    -By default, the Sender will verify the server's certificate, but this check can be disabled by setting this option to unsafe_off.
    -This is useful in non-production environments where self-signed certificates might be used, but should be avoided in production if possible. -
  • -
  • tls_ca: string - Path to a file containing the root CA's certificate in PEM format.
    -Can be useful when self-signed certificates are used, otherwise should not be set. -
  • -
-
-Auto flush options -
    -
  • auto_flush: enum, accepted values: on, off - The Sender automatically flushes the buffer by default. This can be switched off -by setting this option to off.
    -When disabled, the flush() method of the Sender has to be called explicitly to make sure data is sent to the server.
    -Manual buffer flushing can be useful, especially when we want to control transaction boundaries.
    -When the HTTP protocol is used, each flush results in a single HTTP request, which becomes a single transaction on the server side.
    -The transaction either succeeds, and all rows sent in the request are inserted; or it fails, and none of the rows make it into the database. -
  • -
  • auto_flush_rows: integer - The number of rows that will trigger a flush. When set to 0, row-based flushing is disabled.
    -The Sender will default this parameter to 75000 rows when HTTP protocol is used, and to 600 in case of TCP protocol. -
  • -
  • auto_flush_interval: integer - The number of milliseconds that will trigger a flush, default value is 1000. -When set to 0, interval-based flushing is disabled.
    -Note that the setting is checked only when a new row is added to the buffer. There is no timer registered to flush the buffer automatically. -
  • -
-
-Buffer sizing options -
    -
  • init_buf_size: integer - Initial buffer size, defaults to 64 KiB in the Sender. -
  • -
  • max_buf_size: integer - Maximum buffer size, defaults to 100 MiB in the Sender.
    -If the buffer would need to be extended beyond the maximum size, an error is thrown. -
  • -
-
-HTTP request specific options -
    -
  • request_timeout: integer - The time in milliseconds to wait for a response from the server, set to 10 seconds by default.
    -This is in addition to the calculation derived from the request_min_throughput parameter. -
  • -
  • request_min_throughput: integer - Minimum expected throughput in bytes per second for HTTP requests, set to 100 KiB/s seconds by default.
    -If the throughput is lower than this value, the connection will time out. This is used to calculate an additional -timeout on top of request_timeout. This is useful for large requests. You can set this value to 0 to disable this logic. -
  • -
  • retry_timeout: integer - The time in milliseconds to continue retrying after a failed HTTP request, set to 10 seconds by default.
    -The interval between retries is an exponential backoff starting at 10ms and doubling after each failed attempt up to a maximum of 1 second. -
  • -
-
-Other options -
    -
  • stdlib_http: enum, accepted values: on, off - With HTTP protocol the Undici library is used by default. By setting this option -to on the client switches to node's core http and https modules. -
  • -
  • max_name_len: integer - The maximum length of a table or column name, the Sender defaults this parameter to 127.
    -Recommended to use the same setting as the server, which also uses 127 by default. -
  • -
- - -
- -
-
- - - - -

Constructor

- - - -

new SenderOptions(configurationString, extraOptions)

- - - - - - -
- Creates a Sender options object by parsing the provided configuration string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
configurationString - - -string - - - - Configuration string.
extraOptions - - -object - - - - Optional extra configuration.
-- 'log' is a logging function used by the Sender.
-Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
-- 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
-Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async, static) fromConfig(configurationString, extraOptions) → {SenderOptions}

- - - - - - -
- Creates a Sender options object by parsing the provided configuration string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
configurationString - - -string - - - - Configuration string.
extraOptions - - -object - - - - Optional extra configuration.
-- 'log' is a logging function used by the Sender.
-Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
-- 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
-Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- A Sender configuration object initialized from the provided configuration string. -
- - - -
-
- Type -
-
- -SenderOptions - - -
-
- - - - - - - - - - - - - -

(async, static) fromEnv(extraOptions) → {SenderOptions}

- - - - - - -
- Creates a Sender options object by parsing the configuration string set in the QDB_CLIENT_CONF environment variable. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
extraOptions - - -object - - - - Optional extra configuration.
-- 'log' is a logging function used by the Sender.
-Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
-- 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
-Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- A Sender configuration object initialized from the QDB_CLIENT_CONF environment variable. -
- - - -
-
- Type -
-
- -SenderOptions - - -
-
- - - - - - - - - - - - - -

(async, static) resolveAuto(options)

- - - - - - -
- Resolves the protocol version, if it is set to 'auto'.
-If TCP transport is used, the protocol version will default to 1. -In case of HTTP transport the /settings endpoint of the database is used to find the protocol versions -supported by the server, and the highest will be selected. -When calling the /settings endpoint the timeout and TLs options are used from the options object. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - SenderOptions instance needs resolving protocol version
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/TcpTransport.html b/docs/TcpTransport.html deleted file mode 100644 index 1b49f18..0000000 --- a/docs/TcpTransport.html +++ /dev/null @@ -1,695 +0,0 @@ - - - - - JSDoc: Class: TcpTransport - - - - - - - - - - -
- -

Class: TcpTransport

- - - - - - -
- -
- -

TcpTransport(options)

- -
TCP transport implementation.
-Supports both plain TCP or secure TLS-encrypted connections with configurable JWK token authentication.
- - -
- -
-
- - - - -

Constructor

- - - -

new TcpTransport(options)

- - - - - - -
- Creates a new TcpTransport instance. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - Sender configuration object containing connection and authentication details
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if required options are missing or protocol is not 'tcp' or 'tcps' - -
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async) close()

- - - - - - -
- Closes the TCP connection to the database. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

connect()

- - - - - - -
- Creates a TCP connection to the database. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if connection fails or authentication is rejected - -
- - - - - -
Returns:
- - -
- Promise resolving to true if the connection is established successfully -
- - - - - - - - - - - - - - - -

getDefaultAutoFlushRows()

- - - - - - -
- Gets the default auto-flush row count for TCP transport. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Default number of rows that trigger auto-flush -
- - - - - - - - - - - - - - - -

send(data)

- - - - - - -
- Sends data over the established TCP connection. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -Buffer - - - - Buffer containing the data to send
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if the data could not be written to the socket - -
- - - - - -
Returns:
- - -
- Promise resolving to true if data was sent successfully -
- - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/UndiciTransport.html b/docs/UndiciTransport.html deleted file mode 100644 index 75def4d..0000000 --- a/docs/UndiciTransport.html +++ /dev/null @@ -1,395 +0,0 @@ - - - - - JSDoc: Class: UndiciTransport - - - - - - - - - - -
- -

Class: UndiciTransport

- - - - - - -
- -
- -

UndiciTransport(options)

- -
HTTP transport implementation using the Undici library.
-Provides high-performance HTTP requests with connection pooling and retry logic.
-Supports both HTTP and HTTPS protocols with configurable authentication.
- - -
- -
-
- - - - -

Constructor

- - - -

new UndiciTransport(options)

- - - - - - -
- Creates a new UndiciTransport instance. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - Sender configuration object containing connection and retry settings
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if the protocol is not 'http' or 'https' - -
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async) send(data)

- - - - - - -
- Sends data to QuestDB using HTTP POST. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -Buffer - - - - Buffer containing the data to send
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if request fails after all retries or times out - -
- - - - - -
Returns:
- - -
- Promise resolving to true if data was sent successfully -
- - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/assets/hierarchy.js b/docs/assets/hierarchy.js new file mode 100644 index 0000000..0de0b65 --- /dev/null +++ b/docs/assets/hierarchy.js @@ -0,0 +1 @@ +window.hierarchyData = "eJx1jsEKwjAQRP9lztFiglbyG/YmPYRkS4NpWjbxVPLvEkUpiqeBnZl9s4LnOSfoq5JtL8A0BLLZzzFBr1CyrRLNRNC4UHTEHZuYlpkzBG4+Omh5PAncOUDDx0w8GEup+UrvxzwFCNhgUoJGTm5X67tPpZqjD44p1j2q7YuAUtsFnV1+8Qd5fuOfzyk129xf8OtQSnkAhsZX2g==" \ No newline at end of file diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css new file mode 100644 index 0000000..dfbb2d4 --- /dev/null +++ b/docs/assets/highlight.css @@ -0,0 +1,99 @@ +:root { + --light-hl-0: #008000; + --dark-hl-0: #6A9955; + --light-hl-1: #795E26; + --dark-hl-1: #DCDCAA; + --light-hl-2: #000000; + --dark-hl-2: #D4D4D4; + --light-hl-3: #A31515; + --dark-hl-3: #CE9178; + --light-hl-4: #0000FF; + --dark-hl-4: #569CD6; + --light-hl-5: #AF00DB; + --dark-hl-5: #C586C0; + --light-hl-6: #001080; + --dark-hl-6: #9CDCFE; + --light-hl-7: #0070C1; + --dark-hl-7: #4FC1FF; + --light-hl-8: #098658; + --dark-hl-8: #B5CEA8; + --light-hl-9: #000000FF; + --dark-hl-9: #D4D4D4; + --light-hl-10: #267F99; + --dark-hl-10: #4EC9B0; + --light-code-background: #FFFFFF; + --dark-code-background: #1E1E1E; +} + +@media (prefers-color-scheme: light) { :root { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); + --hl-7: var(--light-hl-7); + --hl-8: var(--light-hl-8); + --hl-9: var(--light-hl-9); + --hl-10: var(--light-hl-10); + --code-background: var(--light-code-background); +} } + +@media (prefers-color-scheme: dark) { :root { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); + --hl-7: var(--dark-hl-7); + --hl-8: var(--dark-hl-8); + --hl-9: var(--dark-hl-9); + --hl-10: var(--dark-hl-10); + --code-background: var(--dark-code-background); +} } + +:root[data-theme='light'] { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); + --hl-7: var(--light-hl-7); + --hl-8: var(--light-hl-8); + --hl-9: var(--light-hl-9); + --hl-10: var(--light-hl-10); + --code-background: var(--light-code-background); +} + +:root[data-theme='dark'] { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); + --hl-7: var(--dark-hl-7); + --hl-8: var(--dark-hl-8); + --hl-9: var(--dark-hl-9); + --hl-10: var(--dark-hl-10); + --code-background: var(--dark-code-background); +} + +.hl-0 { color: var(--hl-0); } +.hl-1 { color: var(--hl-1); } +.hl-2 { color: var(--hl-2); } +.hl-3 { color: var(--hl-3); } +.hl-4 { color: var(--hl-4); } +.hl-5 { color: var(--hl-5); } +.hl-6 { color: var(--hl-6); } +.hl-7 { color: var(--hl-7); } +.hl-8 { color: var(--hl-8); } +.hl-9 { color: var(--hl-9); } +.hl-10 { color: var(--hl-10); } +pre, code { background: var(--code-background); } diff --git a/docs/assets/icons.js b/docs/assets/icons.js new file mode 100644 index 0000000..58882d7 --- /dev/null +++ b/docs/assets/icons.js @@ -0,0 +1,18 @@ +(function() { + addIcons(); + function addIcons() { + if (document.readyState === "loading") return document.addEventListener("DOMContentLoaded", addIcons); + const svg = document.body.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg")); + svg.innerHTML = `MMNEPVFCICPMFPCPTTAAATR`; + svg.style.display = "none"; + if (location.protocol === "file:") updateUseElements(); + } + + function updateUseElements() { + document.querySelectorAll("use").forEach(el => { + if (el.getAttribute("href").includes("#icon-")) { + el.setAttribute("href", el.getAttribute("href").replace(/.*#/, "#")); + } + }); + } +})() \ No newline at end of file diff --git a/docs/assets/icons.svg b/docs/assets/icons.svg new file mode 100644 index 0000000..50ad579 --- /dev/null +++ b/docs/assets/icons.svg @@ -0,0 +1 @@ +MMNEPVFCICPMFPCPTTAAATR \ No newline at end of file diff --git a/docs/assets/main.js b/docs/assets/main.js new file mode 100644 index 0000000..19bbb7a --- /dev/null +++ b/docs/assets/main.js @@ -0,0 +1,60 @@ +"use strict"; +window.translations={"copy":"Copy","copied":"Copied!","normally_hidden":"This member is normally hidden due to your filter settings.","hierarchy_expand":"Expand","hierarchy_collapse":"Collapse","folder":"Folder","search_index_not_available":"The search index is not available","search_no_results_found_for_0":"No results found for {0}","kind_1":"Project","kind_2":"Module","kind_4":"Namespace","kind_8":"Enumeration","kind_16":"Enumeration Member","kind_32":"Variable","kind_64":"Function","kind_128":"Class","kind_256":"Interface","kind_512":"Constructor","kind_1024":"Property","kind_2048":"Method","kind_4096":"Call Signature","kind_8192":"Index Signature","kind_16384":"Constructor Signature","kind_32768":"Parameter","kind_65536":"Type Literal","kind_131072":"Type Parameter","kind_262144":"Accessor","kind_524288":"Get Signature","kind_1048576":"Set Signature","kind_2097152":"Type Alias","kind_4194304":"Reference","kind_8388608":"Document"}; +"use strict";(()=>{var Ke=Object.create;var he=Object.defineProperty;var Ge=Object.getOwnPropertyDescriptor;var Ze=Object.getOwnPropertyNames;var Xe=Object.getPrototypeOf,Ye=Object.prototype.hasOwnProperty;var et=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var tt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ze(e))!Ye.call(t,i)&&i!==n&&he(t,i,{get:()=>e[i],enumerable:!(r=Ge(e,i))||r.enumerable});return t};var nt=(t,e,n)=>(n=t!=null?Ke(Xe(t)):{},tt(e||!t||!t.__esModule?he(n,"default",{value:t,enumerable:!0}):n,t));var ye=et((me,ge)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=function(e){return function(n){e.console&&console.warn&&console.warn(n)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var d=t.utils.clone(n)||{};d.position=[a,l],d.index=s.length,s.push(new t.Token(r.slice(a,o),d))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(oc?d+=2:a==c&&(n+=r[l+1]*i[d+1],l+=2,d+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var c=s.node.edges["*"];else{var c=new t.TokenSet;s.node.edges["*"]=c}if(s.str.length==0&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var d=s.str.charAt(0),f=s.str.charAt(1),p;f in s.node.edges?p=s.node.edges[f]:(p=new t.TokenSet,s.node.edges[f]=p),s.str.length==1&&(p.final=!0),i.push({node:p,editsRemaining:s.editsRemaining-1,str:d+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),c=0;c1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,n){typeof define=="function"&&define.amd?define(n):typeof me=="object"?ge.exports=n():e.lunr=n()}(this,function(){return t})})()});var M,G={getItem(){return null},setItem(){}},K;try{K=localStorage,M=K}catch{K=G,M=G}var S={getItem:t=>M.getItem(t),setItem:(t,e)=>M.setItem(t,e),disableWritingLocalStorage(){M=G},disable(){localStorage.clear(),M=G},enable(){M=K}};window.TypeDoc||={disableWritingLocalStorage(){S.disableWritingLocalStorage()},disableLocalStorage:()=>{S.disable()},enableLocalStorage:()=>{S.enable()}};window.translations||={copy:"Copy",copied:"Copied!",normally_hidden:"This member is normally hidden due to your filter settings.",hierarchy_expand:"Expand",hierarchy_collapse:"Collapse",search_index_not_available:"The search index is not available",search_no_results_found_for_0:"No results found for {0}",folder:"Folder",kind_1:"Project",kind_2:"Module",kind_4:"Namespace",kind_8:"Enumeration",kind_16:"Enumeration Member",kind_32:"Variable",kind_64:"Function",kind_128:"Class",kind_256:"Interface",kind_512:"Constructor",kind_1024:"Property",kind_2048:"Method",kind_4096:"Call Signature",kind_8192:"Index Signature",kind_16384:"Constructor Signature",kind_32768:"Parameter",kind_65536:"Type Literal",kind_131072:"Type Parameter",kind_262144:"Accessor",kind_524288:"Get Signature",kind_1048576:"Set Signature",kind_2097152:"Type Alias",kind_4194304:"Reference",kind_8388608:"Document"};var pe=[];function X(t,e){pe.push({selector:e,constructor:t})}var Z=class{alwaysVisibleMember=null;constructor(){this.createComponents(document.body),this.ensureFocusedElementVisible(),this.listenForCodeCopies(),window.addEventListener("hashchange",()=>this.ensureFocusedElementVisible()),document.body.style.display||(this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}createComponents(e){pe.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r,app:this}),r.dataset.hasInstance=String(!0))})})}filterChanged(){this.ensureFocusedElementVisible()}showPage(){document.body.style.display&&(document.body.style.removeProperty("display"),this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}scrollToHash(){if(location.hash){let e=document.getElementById(location.hash.substring(1));if(!e)return;e.scrollIntoView({behavior:"instant",block:"start"})}}ensureActivePageVisible(){let e=document.querySelector(".tsd-navigation .current"),n=e?.parentElement;for(;n&&!n.classList.contains(".tsd-navigation");)n instanceof HTMLDetailsElement&&(n.open=!0),n=n.parentElement;if(e&&!rt(e)){let r=e.getBoundingClientRect().top-document.documentElement.clientHeight/4;document.querySelector(".site-menu").scrollTop=r,document.querySelector(".col-sidebar").scrollTop=r}}updateIndexVisibility(){let e=document.querySelector(".tsd-index-content"),n=e?.open;e&&(e.open=!0),document.querySelectorAll(".tsd-index-section").forEach(r=>{r.style.display="block";let i=Array.from(r.querySelectorAll(".tsd-index-link")).every(s=>s.offsetParent==null);r.style.display=i?"none":"block"}),e&&(e.open=n)}ensureFocusedElementVisible(){if(this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null),!location.hash)return;let e=document.getElementById(location.hash.substring(1));if(!e)return;let n=e.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(!n)return;let r=n.offsetParent==null,i=n;for(;i!==document.body;)i instanceof HTMLDetailsElement&&(i.open=!0),i=i.parentElement;if(n.offsetParent==null){this.alwaysVisibleMember=n,n.classList.add("always-visible");let s=document.createElement("p");s.classList.add("warning"),s.textContent=window.translations.normally_hidden,n.prepend(s)}r&&e.scrollIntoView()}listenForCodeCopies(){document.querySelectorAll("pre > button").forEach(e=>{let n;e.addEventListener("click",()=>{e.previousElementSibling instanceof HTMLElement&&navigator.clipboard.writeText(e.previousElementSibling.innerText.trim()),e.textContent=window.translations.copied,e.classList.add("visible"),clearTimeout(n),n=setTimeout(()=>{e.classList.remove("visible"),n=setTimeout(()=>{e.textContent=window.translations.copy},100)},1e3)})})}};function rt(t){let e=t.getBoundingClientRect(),n=Math.max(document.documentElement.clientHeight,window.innerHeight);return!(e.bottom<0||e.top-n>=0)}var fe=(t,e=100)=>{let n;return()=>{clearTimeout(n),n=setTimeout(()=>t(),e)}};var Ie=nt(ye(),1);async function R(t){let e=Uint8Array.from(atob(t),s=>s.charCodeAt(0)),r=new Blob([e]).stream().pipeThrough(new DecompressionStream("deflate")),i=await new Response(r).text();return JSON.parse(i)}var Y="closing",ae="tsd-overlay";function it(){let t=Math.abs(window.innerWidth-document.documentElement.clientWidth);document.body.style.overflow="hidden",document.body.style.paddingRight=`${t}px`}function st(){document.body.style.removeProperty("overflow"),document.body.style.removeProperty("padding-right")}function xe(t,e){t.addEventListener("animationend",()=>{t.classList.contains(Y)&&(t.classList.remove(Y),document.getElementById(ae)?.remove(),t.close(),st())}),t.addEventListener("cancel",n=>{n.preventDefault(),ve(t)}),e?.closeOnClick&&document.addEventListener("click",n=>{t.open&&!t.contains(n.target)&&ve(t)},!0)}function Ee(t){if(t.open)return;let e=document.createElement("div");e.id=ae,document.body.appendChild(e),t.showModal(),it()}function ve(t){if(!t.open)return;document.getElementById(ae)?.classList.add(Y),t.classList.add(Y)}var I=class{el;app;constructor(e){this.el=e.el,this.app=e.app}};var be=document.head.appendChild(document.createElement("style"));be.dataset.for="filters";var le={};function we(t){for(let e of t.split(/\s+/))if(le.hasOwnProperty(e)&&!le[e])return!0;return!1}var ee=class extends I{key;value;constructor(e){super(e),this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),be.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } +`,this.app.updateIndexVisibility()}fromLocalStorage(){let e=S.getItem(this.key);return e?e==="true":this.el.checked}setLocalStorage(e){S.setItem(this.key,e.toString()),this.value=e,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),le[`tsd-is-${this.el.name}`]=this.value,this.app.filterChanged(),this.app.updateIndexVisibility()}};var Le=0;async function Se(t,e){if(!window.searchData)return;let n=await R(window.searchData);t.data=n,t.index=Ie.Index.load(n.index),e.innerHTML=""}function _e(){let t=document.getElementById("tsd-search-trigger"),e=document.getElementById("tsd-search"),n=document.getElementById("tsd-search-input"),r=document.getElementById("tsd-search-results"),i=document.getElementById("tsd-search-script"),s=document.getElementById("tsd-search-status");if(!(t&&e&&n&&r&&i&&s))throw new Error("Search controls missing");let o={base:document.documentElement.dataset.base};o.base.endsWith("/")||(o.base+="/"),i.addEventListener("error",()=>{let a=window.translations.search_index_not_available;Pe(s,a)}),i.addEventListener("load",()=>{Se(o,s)}),Se(o,s),ot({trigger:t,searchEl:e,results:r,field:n,status:s},o)}function ot(t,e){let{field:n,results:r,searchEl:i,status:s,trigger:o}=t;xe(i,{closeOnClick:!0});function a(){Ee(i),n.setSelectionRange(0,n.value.length)}o.addEventListener("click",a),n.addEventListener("input",fe(()=>{at(r,n,s,e)},200)),n.addEventListener("keydown",l=>{if(r.childElementCount===0||l.ctrlKey||l.metaKey||l.altKey)return;let d=n.getAttribute("aria-activedescendant"),f=d?document.getElementById(d):null;if(f){let p=!1,v=!1;switch(l.key){case"Home":case"End":case"ArrowLeft":case"ArrowRight":v=!0;break;case"ArrowDown":case"ArrowUp":p=l.shiftKey;break}(p||v)&&ke(n)}if(!l.shiftKey)switch(l.key){case"Enter":f?.querySelector("a")?.click();break;case"ArrowUp":Te(r,n,f,-1),l.preventDefault();break;case"ArrowDown":Te(r,n,f,1),l.preventDefault();break}});function c(){ke(n)}n.addEventListener("change",c),n.addEventListener("blur",c),n.addEventListener("click",c),document.body.addEventListener("keydown",l=>{if(l.altKey||l.metaKey||l.shiftKey)return;let d=l.ctrlKey&&l.key==="k",f=!l.ctrlKey&&!ut()&&l.key==="/";(d||f)&&(l.preventDefault(),a())})}function at(t,e,n,r){if(!r.index||!r.data)return;t.innerHTML="",n.innerHTML="",Le+=1;let i=e.value.trim(),s;if(i){let a=i.split(" ").map(c=>c.length?`*${c}*`:"").join(" ");s=r.index.search(a).filter(({ref:c})=>{let l=r.data.rows[Number(c)].classes;return!l||!we(l)})}else s=[];if(s.length===0&&i){let a=window.translations.search_no_results_found_for_0.replace("{0}",` "${te(i)}" `);Pe(n,a);return}for(let a=0;ac.score-a.score);let o=Math.min(10,s.length);for(let a=0;a`,f=Ce(c.name,i);globalThis.DEBUG_SEARCH_WEIGHTS&&(f+=` (score: ${s[a].score.toFixed(2)})`),c.parent&&(f=` + ${Ce(c.parent,i)}.${f}`);let p=document.createElement("li");p.id=`tsd-search:${Le}-${a}`,p.role="option",p.ariaSelected="false",p.classList.value=c.classes??"";let v=document.createElement("a");v.tabIndex=-1,v.href=r.base+c.url,v.innerHTML=d+`${f}`,p.append(v),t.appendChild(p)}}function Te(t,e,n,r){let i;if(r===1?i=n?.nextElementSibling||t.firstElementChild:i=n?.previousElementSibling||t.lastElementChild,i!==n){if(!i||i.role!=="option"){console.error("Option missing");return}i.ariaSelected="true",i.scrollIntoView({behavior:"smooth",block:"nearest"}),e.setAttribute("aria-activedescendant",i.id),n?.setAttribute("aria-selected","false")}}function ke(t){let e=t.getAttribute("aria-activedescendant");(e?document.getElementById(e):null)?.setAttribute("aria-selected","false"),t.setAttribute("aria-activedescendant","")}function Ce(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(te(t.substring(s,o)),`${te(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(te(t.substring(s))),i.join("")}var lt={"&":"&","<":"<",">":">","'":"'",'"':"""};function te(t){return t.replace(/[&<>"'"]/g,e=>lt[e])}function Pe(t,e){t.innerHTML=e?`
${e}
`:""}var ct=["button","checkbox","file","hidden","image","radio","range","reset","submit"];function ut(){let t=document.activeElement;return t?t.isContentEditable||t.tagName==="TEXTAREA"||t.tagName==="SEARCH"?!0:t.tagName==="INPUT"&&!ct.includes(t.type):!1}var D="mousedown",Me="mousemove",$="mouseup",ne={x:0,y:0},Qe=!1,ce=!1,dt=!1,F=!1,Oe=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(Oe?"is-mobile":"not-mobile");Oe&&"ontouchstart"in document.documentElement&&(dt=!0,D="touchstart",Me="touchmove",$="touchend");document.addEventListener(D,t=>{ce=!0,F=!1;let e=D=="touchstart"?t.targetTouches[0]:t;ne.y=e.pageY||0,ne.x=e.pageX||0});document.addEventListener(Me,t=>{if(ce&&!F){let e=D=="touchstart"?t.targetTouches[0]:t,n=ne.x-(e.pageX||0),r=ne.y-(e.pageY||0);F=Math.sqrt(n*n+r*r)>10}});document.addEventListener($,()=>{ce=!1});document.addEventListener("click",t=>{Qe&&(t.preventDefault(),t.stopImmediatePropagation(),Qe=!1)});var re=class extends I{active;className;constructor(e){super(e),this.className=this.el.dataset.toggle||"",this.el.addEventListener($,n=>this.onPointerUp(n)),this.el.addEventListener("click",n=>n.preventDefault()),document.addEventListener(D,n=>this.onDocumentPointerDown(n)),document.addEventListener($,n=>this.onDocumentPointerUp(n))}setActive(e){if(this.active==e)return;this.active=e,document.documentElement.classList.toggle("has-"+this.className,e),this.el.classList.toggle("active",e);let n=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(n),setTimeout(()=>document.documentElement.classList.remove(n),500)}onPointerUp(e){F||(this.setActive(!0),e.preventDefault())}onDocumentPointerDown(e){if(this.active){if(e.target.closest(".col-sidebar, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(e){if(!F&&this.active&&e.target.closest(".col-sidebar")){let n=e.target.closest("a");if(n){let r=window.location.href;r.indexOf("#")!=-1&&(r=r.substring(0,r.indexOf("#"))),n.href.substring(0,r.length)==r&&setTimeout(()=>this.setActive(!1),250)}}}};var ue=new Map,de=class{open;accordions=[];key;constructor(e,n){this.key=e,this.open=n}add(e){this.accordions.push(e),e.open=this.open,e.addEventListener("toggle",()=>{this.toggle(e.open)})}toggle(e){for(let n of this.accordions)n.open=e;S.setItem(this.key,e.toString())}},ie=class extends I{constructor(e){super(e);let n=this.el.querySelector("summary"),r=n.querySelector("a");r&&r.addEventListener("click",()=>{location.assign(r.href)});let i=`tsd-accordion-${n.dataset.key??n.textContent.trim().replace(/\s+/g,"-").toLowerCase()}`,s;if(ue.has(i))s=ue.get(i);else{let o=S.getItem(i),a=o?o==="true":this.el.open;s=new de(i,a),ue.set(i,s)}s.add(this.el)}};function He(t){let e=S.getItem("tsd-theme")||"os";t.value=e,Ae(e),t.addEventListener("change",()=>{S.setItem("tsd-theme",t.value),Ae(t.value)})}function Ae(t){document.documentElement.dataset.theme=t}var se;function Ne(){let t=document.getElementById("tsd-nav-script");t&&(t.addEventListener("load",Re),Re())}async function Re(){let t=document.getElementById("tsd-nav-container");if(!t||!window.navigationData)return;let e=await R(window.navigationData);se=document.documentElement.dataset.base,se.endsWith("/")||(se+="/"),t.innerHTML="";for(let n of e)Be(n,t,[]);window.app.createComponents(t),window.app.showPage(),window.app.ensureActivePageVisible()}function Be(t,e,n){let r=e.appendChild(document.createElement("li"));if(t.children){let i=[...n,t.text],s=r.appendChild(document.createElement("details"));s.className=t.class?`${t.class} tsd-accordion`:"tsd-accordion";let o=s.appendChild(document.createElement("summary"));o.className="tsd-accordion-summary",o.dataset.key=i.join("$"),o.innerHTML='',De(t,o);let a=s.appendChild(document.createElement("div"));a.className="tsd-accordion-details";let c=a.appendChild(document.createElement("ul"));c.className="tsd-nested-navigation";for(let l of t.children)Be(l,c,i)}else De(t,r,t.class)}function De(t,e,n){if(t.path){let r=e.appendChild(document.createElement("a"));if(r.href=se+t.path,n&&(r.className=n),location.pathname===r.pathname&&!r.href.includes("#")&&(r.classList.add("current"),r.ariaCurrent="page"),t.kind){let i=window.translations[`kind_${t.kind}`].replaceAll('"',""");r.innerHTML=``}r.appendChild(Fe(t.text,document.createElement("span")))}else{let r=e.appendChild(document.createElement("span")),i=window.translations.folder.replaceAll('"',""");r.innerHTML=``,r.appendChild(Fe(t.text,document.createElement("span")))}}function Fe(t,e){let n=t.split(/(?<=[^A-Z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?<=[_-])(?=[^_-])/);for(let r=0;r{let i=r.target;for(;i.parentElement&&i.parentElement.tagName!="LI";)i=i.parentElement;i.dataset.dropdown&&(i.dataset.dropdown=String(i.dataset.dropdown!=="true"))});let t=new Map,e=new Set;for(let r of document.querySelectorAll(".tsd-full-hierarchy [data-refl]")){let i=r.querySelector("ul");t.has(r.dataset.refl)?e.add(r.dataset.refl):i&&t.set(r.dataset.refl,i)}for(let r of e)n(r);function n(r){let i=t.get(r).cloneNode(!0);i.querySelectorAll("[id]").forEach(s=>{s.removeAttribute("id")}),i.querySelectorAll("[data-dropdown]").forEach(s=>{s.dataset.dropdown="false"});for(let s of document.querySelectorAll(`[data-refl="${r}"]`)){let o=gt(),a=s.querySelector("ul");s.insertBefore(o,a),o.dataset.dropdown=String(!!a),a||s.appendChild(i.cloneNode(!0))}}}function pt(){let t=document.getElementById("tsd-hierarchy-script");t&&(t.addEventListener("load",Ve),Ve())}async function Ve(){let t=document.querySelector(".tsd-panel.tsd-hierarchy:has(h4 a)");if(!t||!window.hierarchyData)return;let e=+t.dataset.refl,n=await R(window.hierarchyData),r=t.querySelector("ul"),i=document.createElement("ul");if(i.classList.add("tsd-hierarchy"),ft(i,n,e),r.querySelectorAll("li").length==i.querySelectorAll("li").length)return;let s=document.createElement("span");s.classList.add("tsd-hierarchy-toggle"),s.textContent=window.translations.hierarchy_expand,t.querySelector("h4 a")?.insertAdjacentElement("afterend",s),s.insertAdjacentText("beforebegin",", "),s.addEventListener("click",()=>{s.textContent===window.translations.hierarchy_expand?(r.insertAdjacentElement("afterend",i),r.remove(),s.textContent=window.translations.hierarchy_collapse):(i.insertAdjacentElement("afterend",r),i.remove(),s.textContent=window.translations.hierarchy_expand)})}function ft(t,e,n){let r=e.roots.filter(i=>mt(e,i,n));for(let i of r)t.appendChild(je(e,i,n))}function je(t,e,n,r=new Set){if(r.has(e))return;r.add(e);let i=t.reflections[e],s=document.createElement("li");if(s.classList.add("tsd-hierarchy-item"),e===n){let o=s.appendChild(document.createElement("span"));o.textContent=i.name,o.classList.add("tsd-hierarchy-target")}else{for(let a of i.uniqueNameParents||[]){let c=t.reflections[a],l=s.appendChild(document.createElement("a"));l.textContent=c.name,l.href=oe+c.url,l.className=c.class+" tsd-signature-type",s.append(document.createTextNode("."))}let o=s.appendChild(document.createElement("a"));o.textContent=t.reflections[e].name,o.href=oe+i.url,o.className=i.class+" tsd-signature-type"}if(i.children){let o=s.appendChild(document.createElement("ul"));o.classList.add("tsd-hierarchy");for(let a of i.children){let c=je(t,a,n,r);c&&o.appendChild(c)}}return r.delete(e),s}function mt(t,e,n){if(e===n)return!0;let r=new Set,i=[t.reflections[e]];for(;i.length;){let s=i.pop();if(!r.has(s)){r.add(s);for(let o of s.children||[]){if(o===n)return!0;i.push(t.reflections[o])}}}return!1}function gt(){let t=document.createElementNS("http://www.w3.org/2000/svg","svg");return t.setAttribute("width","20"),t.setAttribute("height","20"),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.innerHTML='',t}X(re,"a[data-toggle]");X(ie,".tsd-accordion");X(ee,".tsd-filter-item input[type=checkbox]");var qe=document.getElementById("tsd-theme");qe&&He(qe);var yt=new Z;Object.defineProperty(window,"app",{value:yt});_e();Ne();$e();"virtualKeyboard"in navigator&&(navigator.virtualKeyboard.overlaysContent=!0);})(); +/*! Bundled license information: + +lunr/lunr.js: + (** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + *) + (*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + *) + (*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + *) +*/ diff --git a/docs/assets/navigation.js b/docs/assets/navigation.js new file mode 100644 index 0000000..35af7fd --- /dev/null +++ b/docs/assets/navigation.js @@ -0,0 +1 @@ +window.navigationData = "eJyN0bsOgjAUBuB3OTMRaYIXRhMTBxMHwcU4NFCwEUrTHhOM8d0dGGwLFNf+PV/O5foGZB1CAmcmCqZ2z7Jk6hJBAJLiHRLIa6o106GdL+7Y1BDAg4sCkohsPsG4RGYk8q/0c7hApkqaO5QNkXhlQMe2qkwCX5LpsH916pbbdRQTo3bfoaInibwV2hXMbM7pex1Ag2nGOWuc/uPUZn0bPSDKVFGhZatwCFixz8lEwXPukZwP81cesQarmeDs5aS5b0Iz9TWV8oZppI3MBEf37FY4fvfbFxuAI2Y=" \ No newline at end of file diff --git a/docs/assets/search.js b/docs/assets/search.js new file mode 100644 index 0000000..dedc80f --- /dev/null +++ b/docs/assets/search.js @@ -0,0 +1 @@ +window.searchData = "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"; \ No newline at end of file diff --git a/docs/assets/style.css b/docs/assets/style.css new file mode 100644 index 0000000..5ba5a2a --- /dev/null +++ b/docs/assets/style.css @@ -0,0 +1,1633 @@ +@layer typedoc { + :root { + --dim-toolbar-contents-height: 2.5rem; + --dim-toolbar-border-bottom-width: 1px; + --dim-header-height: calc( + var(--dim-toolbar-border-bottom-width) + + var(--dim-toolbar-contents-height) + ); + + /* 0rem For mobile; unit is required for calculation in `calc` */ + --dim-container-main-margin-y: 0rem; + + --dim-footer-height: 3.5rem; + + --modal-animation-duration: 0.2s; + } + + :root { + /* Light */ + --light-color-background: #f2f4f8; + --light-color-background-secondary: #eff0f1; + /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */ + --light-color-background-active: #d6d8da; + --light-color-background-warning: #e6e600; + --light-color-warning-text: #222; + --light-color-accent: #c5c7c9; + --light-color-active-menu-item: var(--light-color-background-active); + --light-color-text: #222; + --light-color-contrast-text: #000; + --light-color-text-aside: #5e5e5e; + + --light-color-icon-background: var(--light-color-background); + --light-color-icon-text: var(--light-color-text); + + --light-color-comment-tag-text: var(--light-color-text); + --light-color-comment-tag: var(--light-color-background); + + --light-color-link: #1f70c2; + --light-color-focus-outline: #3584e4; + + --light-color-ts-keyword: #056bd6; + --light-color-ts-project: #b111c9; + --light-color-ts-module: var(--light-color-ts-project); + --light-color-ts-namespace: var(--light-color-ts-project); + --light-color-ts-enum: #7e6f15; + --light-color-ts-enum-member: var(--light-color-ts-enum); + --light-color-ts-variable: #4760ec; + --light-color-ts-function: #572be7; + --light-color-ts-class: #1f70c2; + --light-color-ts-interface: #108024; + --light-color-ts-constructor: var(--light-color-ts-class); + --light-color-ts-property: #9f5f30; + --light-color-ts-method: #be3989; + --light-color-ts-reference: #ff4d82; + --light-color-ts-call-signature: var(--light-color-ts-method); + --light-color-ts-index-signature: var(--light-color-ts-property); + --light-color-ts-constructor-signature: var( + --light-color-ts-constructor + ); + --light-color-ts-parameter: var(--light-color-ts-variable); + /* type literal not included as links will never be generated to it */ + --light-color-ts-type-parameter: #a55c0e; + --light-color-ts-accessor: #c73c3c; + --light-color-ts-get-signature: var(--light-color-ts-accessor); + --light-color-ts-set-signature: var(--light-color-ts-accessor); + --light-color-ts-type-alias: #d51270; + /* reference not included as links will be colored with the kind that it points to */ + --light-color-document: #000000; + + --light-color-alert-note: #0969d9; + --light-color-alert-tip: #1a7f37; + --light-color-alert-important: #8250df; + --light-color-alert-warning: #9a6700; + --light-color-alert-caution: #cf222e; + + --light-external-icon: url("data:image/svg+xml;utf8,"); + --light-color-scheme: light; + } + + :root { + /* Dark */ + --dark-color-background: #2b2e33; + --dark-color-background-secondary: #1e2024; + /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */ + --dark-color-background-active: #5d5d6a; + --dark-color-background-warning: #bebe00; + --dark-color-warning-text: #222; + --dark-color-accent: #9096a2; + --dark-color-active-menu-item: var(--dark-color-background-active); + --dark-color-text: #f5f5f5; + --dark-color-contrast-text: #ffffff; + --dark-color-text-aside: #dddddd; + + --dark-color-icon-background: var(--dark-color-background-secondary); + --dark-color-icon-text: var(--dark-color-text); + + --dark-color-comment-tag-text: var(--dark-color-text); + --dark-color-comment-tag: var(--dark-color-background); + + --dark-color-link: #00aff4; + --dark-color-focus-outline: #4c97f2; + + --dark-color-ts-keyword: #3399ff; + --dark-color-ts-project: #e358ff; + --dark-color-ts-module: var(--dark-color-ts-project); + --dark-color-ts-namespace: var(--dark-color-ts-project); + --dark-color-ts-enum: #f4d93e; + --dark-color-ts-enum-member: var(--dark-color-ts-enum); + --dark-color-ts-variable: #798dff; + --dark-color-ts-function: #a280ff; + --dark-color-ts-class: #8ac4ff; + --dark-color-ts-interface: #6cff87; + --dark-color-ts-constructor: var(--dark-color-ts-class); + --dark-color-ts-property: #ff984d; + --dark-color-ts-method: #ff4db8; + --dark-color-ts-reference: #ff4d82; + --dark-color-ts-call-signature: var(--dark-color-ts-method); + --dark-color-ts-index-signature: var(--dark-color-ts-property); + --dark-color-ts-constructor-signature: var(--dark-color-ts-constructor); + --dark-color-ts-parameter: var(--dark-color-ts-variable); + /* type literal not included as links will never be generated to it */ + --dark-color-ts-type-parameter: #e07d13; + --dark-color-ts-accessor: #ff6060; + --dark-color-ts-get-signature: var(--dark-color-ts-accessor); + --dark-color-ts-set-signature: var(--dark-color-ts-accessor); + --dark-color-ts-type-alias: #ff6492; + /* reference not included as links will be colored with the kind that it points to */ + --dark-color-document: #ffffff; + + --dark-color-alert-note: #0969d9; + --dark-color-alert-tip: #1a7f37; + --dark-color-alert-important: #8250df; + --dark-color-alert-warning: #9a6700; + --dark-color-alert-caution: #cf222e; + + --dark-external-icon: url("data:image/svg+xml;utf8,"); + --dark-color-scheme: dark; + } + + @media (prefers-color-scheme: light) { + :root { + --color-background: var(--light-color-background); + --color-background-secondary: var( + --light-color-background-secondary + ); + --color-background-active: var(--light-color-background-active); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-accent: var(--light-color-accent); + --color-active-menu-item: var(--light-color-active-menu-item); + --color-text: var(--light-color-text); + --color-contrast-text: var(--light-color-contrast-text); + --color-text-aside: var(--light-color-text-aside); + + --color-icon-background: var(--light-color-icon-background); + --color-icon-text: var(--light-color-icon-text); + + --color-comment-tag-text: var(--light-color-text); + --color-comment-tag: var(--light-color-background); + + --color-link: var(--light-color-link); + --color-focus-outline: var(--light-color-focus-outline); + + --color-ts-keyword: var(--light-color-ts-keyword); + --color-ts-project: var(--light-color-ts-project); + --color-ts-module: var(--light-color-ts-module); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-enum-member: var(--light-color-ts-enum-member); + --color-ts-variable: var(--light-color-ts-variable); + --color-ts-function: var(--light-color-ts-function); + --color-ts-class: var(--light-color-ts-class); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-constructor: var(--light-color-ts-constructor); + --color-ts-property: var(--light-color-ts-property); + --color-ts-method: var(--light-color-ts-method); + --color-ts-reference: var(--light-color-ts-reference); + --color-ts-call-signature: var(--light-color-ts-call-signature); + --color-ts-index-signature: var(--light-color-ts-index-signature); + --color-ts-constructor-signature: var( + --light-color-ts-constructor-signature + ); + --color-ts-parameter: var(--light-color-ts-parameter); + --color-ts-type-parameter: var(--light-color-ts-type-parameter); + --color-ts-accessor: var(--light-color-ts-accessor); + --color-ts-get-signature: var(--light-color-ts-get-signature); + --color-ts-set-signature: var(--light-color-ts-set-signature); + --color-ts-type-alias: var(--light-color-ts-type-alias); + --color-document: var(--light-color-document); + + --color-alert-note: var(--light-color-alert-note); + --color-alert-tip: var(--light-color-alert-tip); + --color-alert-important: var(--light-color-alert-important); + --color-alert-warning: var(--light-color-alert-warning); + --color-alert-caution: var(--light-color-alert-caution); + + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); + } + } + + @media (prefers-color-scheme: dark) { + :root { + --color-background: var(--dark-color-background); + --color-background-secondary: var( + --dark-color-background-secondary + ); + --color-background-active: var(--dark-color-background-active); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-accent: var(--dark-color-accent); + --color-active-menu-item: var(--dark-color-active-menu-item); + --color-text: var(--dark-color-text); + --color-contrast-text: var(--dark-color-contrast-text); + --color-text-aside: var(--dark-color-text-aside); + + --color-icon-background: var(--dark-color-icon-background); + --color-icon-text: var(--dark-color-icon-text); + + --color-comment-tag-text: var(--dark-color-text); + --color-comment-tag: var(--dark-color-background); + + --color-link: var(--dark-color-link); + --color-focus-outline: var(--dark-color-focus-outline); + + --color-ts-keyword: var(--dark-color-ts-keyword); + --color-ts-project: var(--dark-color-ts-project); + --color-ts-module: var(--dark-color-ts-module); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-enum-member: var(--dark-color-ts-enum-member); + --color-ts-variable: var(--dark-color-ts-variable); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-constructor: var(--dark-color-ts-constructor); + --color-ts-property: var(--dark-color-ts-property); + --color-ts-method: var(--dark-color-ts-method); + --color-ts-reference: var(--dark-color-ts-reference); + --color-ts-call-signature: var(--dark-color-ts-call-signature); + --color-ts-index-signature: var(--dark-color-ts-index-signature); + --color-ts-constructor-signature: var( + --dark-color-ts-constructor-signature + ); + --color-ts-parameter: var(--dark-color-ts-parameter); + --color-ts-type-parameter: var(--dark-color-ts-type-parameter); + --color-ts-accessor: var(--dark-color-ts-accessor); + --color-ts-get-signature: var(--dark-color-ts-get-signature); + --color-ts-set-signature: var(--dark-color-ts-set-signature); + --color-ts-type-alias: var(--dark-color-ts-type-alias); + --color-document: var(--dark-color-document); + + --color-alert-note: var(--dark-color-alert-note); + --color-alert-tip: var(--dark-color-alert-tip); + --color-alert-important: var(--dark-color-alert-important); + --color-alert-warning: var(--dark-color-alert-warning); + --color-alert-caution: var(--dark-color-alert-caution); + + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); + } + } + + :root[data-theme="light"] { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-background-active: var(--light-color-background-active); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-active-menu-item: var(--light-color-active-menu-item); + --color-text: var(--light-color-text); + --color-contrast-text: var(--light-color-contrast-text); + --color-text-aside: var(--light-color-text-aside); + --color-icon-text: var(--light-color-icon-text); + + --color-comment-tag-text: var(--light-color-text); + --color-comment-tag: var(--light-color-background); + + --color-link: var(--light-color-link); + --color-focus-outline: var(--light-color-focus-outline); + + --color-ts-keyword: var(--light-color-ts-keyword); + --color-ts-project: var(--light-color-ts-project); + --color-ts-module: var(--light-color-ts-module); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-enum-member: var(--light-color-ts-enum-member); + --color-ts-variable: var(--light-color-ts-variable); + --color-ts-function: var(--light-color-ts-function); + --color-ts-class: var(--light-color-ts-class); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-constructor: var(--light-color-ts-constructor); + --color-ts-property: var(--light-color-ts-property); + --color-ts-method: var(--light-color-ts-method); + --color-ts-reference: var(--light-color-ts-reference); + --color-ts-call-signature: var(--light-color-ts-call-signature); + --color-ts-index-signature: var(--light-color-ts-index-signature); + --color-ts-constructor-signature: var( + --light-color-ts-constructor-signature + ); + --color-ts-parameter: var(--light-color-ts-parameter); + --color-ts-type-parameter: var(--light-color-ts-type-parameter); + --color-ts-accessor: var(--light-color-ts-accessor); + --color-ts-get-signature: var(--light-color-ts-get-signature); + --color-ts-set-signature: var(--light-color-ts-set-signature); + --color-ts-type-alias: var(--light-color-ts-type-alias); + --color-document: var(--light-color-document); + + --color-note: var(--light-color-note); + --color-tip: var(--light-color-tip); + --color-important: var(--light-color-important); + --color-warning: var(--light-color-warning); + --color-caution: var(--light-color-caution); + + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); + } + + :root[data-theme="dark"] { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-background-active: var(--dark-color-background-active); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-active-menu-item: var(--dark-color-active-menu-item); + --color-text: var(--dark-color-text); + --color-contrast-text: var(--dark-color-contrast-text); + --color-text-aside: var(--dark-color-text-aside); + --color-icon-text: var(--dark-color-icon-text); + + --color-comment-tag-text: var(--dark-color-text); + --color-comment-tag: var(--dark-color-background); + + --color-link: var(--dark-color-link); + --color-focus-outline: var(--dark-color-focus-outline); + + --color-ts-keyword: var(--dark-color-ts-keyword); + --color-ts-project: var(--dark-color-ts-project); + --color-ts-module: var(--dark-color-ts-module); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-enum-member: var(--dark-color-ts-enum-member); + --color-ts-variable: var(--dark-color-ts-variable); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-constructor: var(--dark-color-ts-constructor); + --color-ts-property: var(--dark-color-ts-property); + --color-ts-method: var(--dark-color-ts-method); + --color-ts-reference: var(--dark-color-ts-reference); + --color-ts-call-signature: var(--dark-color-ts-call-signature); + --color-ts-index-signature: var(--dark-color-ts-index-signature); + --color-ts-constructor-signature: var( + --dark-color-ts-constructor-signature + ); + --color-ts-parameter: var(--dark-color-ts-parameter); + --color-ts-type-parameter: var(--dark-color-ts-type-parameter); + --color-ts-accessor: var(--dark-color-ts-accessor); + --color-ts-get-signature: var(--dark-color-ts-get-signature); + --color-ts-set-signature: var(--dark-color-ts-set-signature); + --color-ts-type-alias: var(--dark-color-ts-type-alias); + --color-document: var(--dark-color-document); + + --color-note: var(--dark-color-note); + --color-tip: var(--dark-color-tip); + --color-important: var(--dark-color-important); + --color-warning: var(--dark-color-warning); + --color-caution: var(--dark-color-caution); + + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); + } + + html { + color-scheme: var(--color-scheme); + @media (prefers-reduced-motion: no-preference) { + scroll-behavior: smooth; + } + } + + *:focus-visible, + .tsd-accordion-summary:focus-visible svg { + outline: 2px solid var(--color-focus-outline); + } + + .always-visible, + .always-visible .tsd-signatures { + display: inherit !important; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + line-height: 1.2; + } + + h1 { + font-size: 1.875rem; + margin: 0.67rem 0; + } + + h2 { + font-size: 1.5rem; + margin: 0.83rem 0; + } + + h3 { + font-size: 1.25rem; + margin: 1rem 0; + } + + h4 { + font-size: 1.05rem; + margin: 1.33rem 0; + } + + h5 { + font-size: 1rem; + margin: 1.5rem 0; + } + + h6 { + font-size: 0.875rem; + margin: 2.33rem 0; + } + + dl, + menu, + ol, + ul { + margin: 1em 0; + } + + dd { + margin: 0 0 0 34px; + } + + .container { + max-width: 1700px; + padding: 0 2rem; + } + + /* Footer */ + footer { + border-top: 1px solid var(--color-accent); + padding-top: 1rem; + padding-bottom: 1rem; + max-height: var(--dim-footer-height); + } + footer > p { + margin: 0 1em; + } + + .container-main { + margin: var(--dim-container-main-margin-y) auto; + /* toolbar, footer, margin */ + min-height: calc( + 100svh - var(--dim-header-height) - var(--dim-footer-height) - + 2 * var(--dim-container-main-margin-y) + ); + } + + @keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + @keyframes fade-out { + from { + opacity: 1; + visibility: visible; + } + to { + opacity: 0; + } + } + @keyframes pop-in-from-right { + from { + transform: translate(100%, 0); + } + to { + transform: translate(0, 0); + } + } + @keyframes pop-out-to-right { + from { + transform: translate(0, 0); + visibility: visible; + } + to { + transform: translate(100%, 0); + } + } + body { + background: var(--color-background); + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", + Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; + font-size: 16px; + color: var(--color-text); + margin: 0; + } + + a { + color: var(--color-link); + text-decoration: none; + } + a:hover { + text-decoration: underline; + } + a.external[target="_blank"] { + background-image: var(--external-icon); + background-position: top 3px right; + background-repeat: no-repeat; + padding-right: 13px; + } + a.tsd-anchor-link { + color: var(--color-text); + } + :target { + scroll-margin-block: calc(var(--dim-header-height) + 0.5rem); + } + + code, + pre { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 0.2em; + margin: 0; + font-size: 0.875rem; + border-radius: 0.8em; + } + + pre { + position: relative; + white-space: pre-wrap; + word-wrap: break-word; + padding: 10px; + border: 1px solid var(--color-accent); + margin-bottom: 8px; + } + pre code { + padding: 0; + font-size: 100%; + } + pre > button { + position: absolute; + top: 10px; + right: 10px; + opacity: 0; + transition: opacity 0.1s; + box-sizing: border-box; + } + pre:hover > button, + pre > button.visible, + pre > button:focus-visible { + opacity: 1; + } + + blockquote { + margin: 1em 0; + padding-left: 1em; + border-left: 4px solid gray; + } + + img { + max-width: 100%; + } + + * { + scrollbar-width: thin; + scrollbar-color: var(--color-accent) var(--color-icon-background); + } + + *::-webkit-scrollbar { + width: 0.75rem; + } + + *::-webkit-scrollbar-track { + background: var(--color-icon-background); + } + + *::-webkit-scrollbar-thumb { + background-color: var(--color-accent); + border-radius: 999rem; + border: 0.25rem solid var(--color-icon-background); + } + + dialog { + border: none; + outline: none; + padding: 0; + background-color: var(--color-background); + } + dialog::backdrop { + display: none; + } + #tsd-overlay { + background-color: rgba(0, 0, 0, 0.5); + position: fixed; + z-index: 9999; + top: 0; + left: 0; + right: 0; + bottom: 0; + animation: fade-in var(--modal-animation-duration) forwards; + } + #tsd-overlay.closing { + animation-name: fade-out; + } + + .tsd-typography { + line-height: 1.333em; + } + .tsd-typography ul { + list-style: square; + padding: 0 0 0 20px; + margin: 0; + } + .tsd-typography .tsd-index-panel h3, + .tsd-index-panel .tsd-typography h3, + .tsd-typography h4, + .tsd-typography h5, + .tsd-typography h6 { + font-size: 1em; + } + .tsd-typography h5, + .tsd-typography h6 { + font-weight: normal; + } + .tsd-typography p, + .tsd-typography ul, + .tsd-typography ol { + margin: 1em 0; + } + .tsd-typography table { + border-collapse: collapse; + border: none; + } + .tsd-typography td, + .tsd-typography th { + padding: 6px 13px; + border: 1px solid var(--color-accent); + } + .tsd-typography thead, + .tsd-typography tr:nth-child(even) { + background-color: var(--color-background-secondary); + } + + .tsd-alert { + padding: 8px 16px; + margin-bottom: 16px; + border-left: 0.25em solid var(--alert-color); + } + .tsd-alert blockquote > :last-child, + .tsd-alert > :last-child { + margin-bottom: 0; + } + .tsd-alert-title { + color: var(--alert-color); + display: inline-flex; + align-items: center; + } + .tsd-alert-title span { + margin-left: 4px; + } + + .tsd-alert-note { + --alert-color: var(--color-alert-note); + } + .tsd-alert-tip { + --alert-color: var(--color-alert-tip); + } + .tsd-alert-important { + --alert-color: var(--color-alert-important); + } + .tsd-alert-warning { + --alert-color: var(--color-alert-warning); + } + .tsd-alert-caution { + --alert-color: var(--color-alert-caution); + } + + .tsd-breadcrumb { + margin: 0; + margin-top: 1rem; + padding: 0; + color: var(--color-text-aside); + } + .tsd-breadcrumb a { + color: var(--color-text-aside); + text-decoration: none; + } + .tsd-breadcrumb a:hover { + text-decoration: underline; + } + .tsd-breadcrumb li { + display: inline; + } + .tsd-breadcrumb li:after { + content: " / "; + } + + .tsd-comment-tags { + display: flex; + flex-direction: column; + } + dl.tsd-comment-tag-group { + display: flex; + align-items: center; + overflow: hidden; + margin: 0.5em 0; + } + dl.tsd-comment-tag-group dt { + display: flex; + margin-right: 0.5em; + font-size: 0.875em; + font-weight: normal; + } + dl.tsd-comment-tag-group dd { + margin: 0; + } + code.tsd-tag { + padding: 0.25em 0.4em; + border: 0.1em solid var(--color-accent); + margin-right: 0.25em; + font-size: 70%; + } + h1 code.tsd-tag:first-of-type { + margin-left: 0.25em; + } + + dl.tsd-comment-tag-group dd:before, + dl.tsd-comment-tag-group dd:after { + content: " "; + } + dl.tsd-comment-tag-group dd pre, + dl.tsd-comment-tag-group dd:after { + clear: both; + } + dl.tsd-comment-tag-group p { + margin: 0; + } + + .tsd-panel.tsd-comment .lead { + font-size: 1.1em; + line-height: 1.333em; + margin-bottom: 2em; + } + .tsd-panel.tsd-comment .lead:last-child { + margin-bottom: 0; + } + + .tsd-filter-visibility h4 { + font-size: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.5rem; + margin: 0; + } + .tsd-filter-item:not(:last-child) { + margin-bottom: 0.5rem; + } + .tsd-filter-input { + display: flex; + width: -moz-fit-content; + width: fit-content; + align-items: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + } + .tsd-filter-input input[type="checkbox"] { + cursor: pointer; + position: absolute; + width: 1.5em; + height: 1.5em; + opacity: 0; + } + .tsd-filter-input input[type="checkbox"]:disabled { + pointer-events: none; + } + .tsd-filter-input svg { + cursor: pointer; + width: 1.5em; + height: 1.5em; + margin-right: 0.5em; + border-radius: 0.33em; + /* Leaving this at full opacity breaks event listeners on Firefox. + Don't remove unless you know what you're doing. */ + opacity: 0.99; + } + .tsd-filter-input input[type="checkbox"]:focus-visible + svg { + outline: 2px solid var(--color-focus-outline); + } + .tsd-checkbox-background { + fill: var(--color-accent); + } + input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { + stroke: var(--color-text); + } + .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { + fill: var(--color-background); + stroke: var(--color-accent); + stroke-width: 0.25rem; + } + .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { + stroke: var(--color-accent); + } + + .settings-label { + font-weight: bold; + text-transform: uppercase; + display: inline-block; + } + + .tsd-filter-visibility .settings-label { + margin: 0.75rem 0 0.5rem 0; + } + + .tsd-theme-toggle .settings-label { + margin: 0.75rem 0.75rem 0 0; + } + + .tsd-hierarchy h4 label:hover span { + text-decoration: underline; + } + + .tsd-hierarchy { + list-style: square; + margin: 0; + } + .tsd-hierarchy-target { + font-weight: bold; + } + .tsd-hierarchy-toggle { + color: var(--color-link); + cursor: pointer; + } + + .tsd-full-hierarchy:not(:last-child) { + margin-bottom: 1em; + padding-bottom: 1em; + border-bottom: 1px solid var(--color-accent); + } + .tsd-full-hierarchy, + .tsd-full-hierarchy ul { + list-style: none; + margin: 0; + padding: 0; + } + .tsd-full-hierarchy ul { + padding-left: 1.5rem; + } + .tsd-full-hierarchy a { + padding: 0.25rem 0 !important; + font-size: 1rem; + display: inline-flex; + align-items: center; + color: var(--color-text); + } + .tsd-full-hierarchy svg[data-dropdown] { + cursor: pointer; + } + .tsd-full-hierarchy svg[data-dropdown="false"] { + transform: rotate(-90deg); + } + .tsd-full-hierarchy svg[data-dropdown="false"] ~ ul { + display: none; + } + + .tsd-panel-group.tsd-index-group { + margin-bottom: 0; + } + .tsd-index-panel .tsd-index-list { + list-style: none; + line-height: 1.333em; + margin: 0; + padding: 0.25rem 0 0 0; + overflow: hidden; + display: grid; + grid-template-columns: repeat(3, 1fr); + column-gap: 1rem; + grid-template-rows: auto; + } + @media (max-width: 1024px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(2, 1fr); + } + } + @media (max-width: 768px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(1, 1fr); + } + } + .tsd-index-panel .tsd-index-list li { + -webkit-page-break-inside: avoid; + -moz-page-break-inside: avoid; + -ms-page-break-inside: avoid; + -o-page-break-inside: avoid; + page-break-inside: avoid; + } + + .tsd-flag { + display: inline-block; + padding: 0.25em 0.4em; + border-radius: 4px; + color: var(--color-comment-tag-text); + background-color: var(--color-comment-tag); + text-indent: 0; + font-size: 75%; + line-height: 1; + font-weight: normal; + } + + .tsd-anchor { + position: relative; + top: -100px; + } + + .tsd-member { + position: relative; + } + .tsd-member .tsd-anchor + h3 { + display: flex; + align-items: center; + margin-top: 0; + margin-bottom: 0; + border-bottom: none; + } + + .tsd-navigation.settings { + margin: 0; + margin-bottom: 1rem; + } + .tsd-navigation > a, + .tsd-navigation .tsd-accordion-summary { + width: calc(100% - 0.25rem); + display: flex; + align-items: center; + } + .tsd-navigation a, + .tsd-navigation summary > span, + .tsd-page-navigation a { + display: flex; + width: calc(100% - 0.25rem); + align-items: center; + padding: 0.25rem; + color: var(--color-text); + text-decoration: none; + box-sizing: border-box; + } + .tsd-navigation a.current, + .tsd-page-navigation a.current { + background: var(--color-active-menu-item); + color: var(--color-contrast-text); + } + .tsd-navigation a:hover, + .tsd-page-navigation a:hover { + text-decoration: underline; + } + .tsd-navigation ul, + .tsd-page-navigation ul { + margin-top: 0; + margin-bottom: 0; + padding: 0; + list-style: none; + } + .tsd-navigation li, + .tsd-page-navigation li { + padding: 0; + max-width: 100%; + } + .tsd-navigation .tsd-nav-link { + display: none; + } + .tsd-nested-navigation { + margin-left: 3rem; + } + .tsd-nested-navigation > li > details { + margin-left: -1.5rem; + } + .tsd-small-nested-navigation { + margin-left: 1.5rem; + } + .tsd-small-nested-navigation > li > details { + margin-left: -1.5rem; + } + + .tsd-page-navigation-section > summary { + padding: 0.25rem; + } + .tsd-page-navigation-section > summary > svg { + margin-right: 0.25rem; + } + .tsd-page-navigation-section > div { + margin-left: 30px; + } + .tsd-page-navigation ul { + padding-left: 1.75rem; + } + + #tsd-sidebar-links a { + margin-top: 0; + margin-bottom: 0.5rem; + line-height: 1.25rem; + } + #tsd-sidebar-links a:last-of-type { + margin-bottom: 0; + } + + a.tsd-index-link { + padding: 0.25rem 0 !important; + font-size: 1rem; + line-height: 1.25rem; + display: inline-flex; + align-items: center; + color: var(--color-text); + } + .tsd-accordion-summary { + list-style-type: none; /* hide marker on non-safari */ + outline: none; /* broken on safari, so just hide it */ + display: flex; + align-items: center; + gap: 0.25rem; + box-sizing: border-box; + } + .tsd-accordion-summary::-webkit-details-marker { + display: none; /* hide marker on safari */ + } + .tsd-accordion-summary, + .tsd-accordion-summary a { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + + cursor: pointer; + } + .tsd-accordion-summary a { + width: calc(100% - 1.5rem); + } + .tsd-accordion-summary > * { + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; + } + /* + * We need to be careful to target the arrow indicating whether the accordion + * is open, but not any other SVGs included in the details element. + */ + .tsd-accordion:not([open]) > .tsd-accordion-summary > svg:first-child { + transform: rotate(-90deg); + } + .tsd-index-content > :not(:first-child) { + margin-top: 0.75rem; + } + .tsd-index-summary { + margin-top: 1.5rem; + margin-bottom: 0.75rem; + display: flex; + align-content: center; + } + + .tsd-no-select { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + .tsd-kind-icon { + margin-right: 0.5rem; + width: 1.25rem; + height: 1.25rem; + min-width: 1.25rem; + min-height: 1.25rem; + } + .tsd-signature > .tsd-kind-icon { + margin-right: 0.8rem; + } + + .tsd-panel { + margin-bottom: 2.5rem; + } + .tsd-panel.tsd-member { + margin-bottom: 4rem; + } + .tsd-panel:empty { + display: none; + } + .tsd-panel > h1, + .tsd-panel > h2, + .tsd-panel > h3 { + margin: 1.5rem -1.5rem 0.75rem -1.5rem; + padding: 0 1.5rem 0.75rem 1.5rem; + } + .tsd-panel > h1.tsd-before-signature, + .tsd-panel > h2.tsd-before-signature, + .tsd-panel > h3.tsd-before-signature { + margin-bottom: 0; + border-bottom: none; + } + + .tsd-panel-group { + margin: 2rem 0; + } + .tsd-panel-group.tsd-index-group { + margin: 2rem 0; + } + .tsd-panel-group.tsd-index-group details { + margin: 2rem 0; + } + .tsd-panel-group > .tsd-accordion-summary { + margin-bottom: 1rem; + } + + #tsd-search[open] { + animation: fade-in var(--modal-animation-duration) ease-out forwards; + } + #tsd-search[open].closing { + animation-name: fade-out; + } + + /* Avoid setting `display` on closed dialog */ + #tsd-search[open] { + display: flex; + flex-direction: column; + padding: 1rem; + width: 32rem; + max-width: 90vw; + max-height: calc(100vh - env(keyboard-inset-height, 0px) - 25vh); + /* Anchor dialog to top */ + margin-top: 10vh; + border-radius: 6px; + will-change: max-height; + } + #tsd-search-input { + box-sizing: border-box; + width: 100%; + padding: 0 0.625rem; /* 10px */ + outline: 0; + border: 2px solid var(--color-accent); + background-color: transparent; + color: var(--color-text); + border-radius: 4px; + height: 2.5rem; + flex: 0 0 auto; + font-size: 0.875rem; + transition: border-color 0.2s, background-color 0.2s; + } + #tsd-search-input:focus-visible { + background-color: var(--color-background-active); + border-color: transparent; + color: var(--color-contrast-text); + } + #tsd-search-input::placeholder { + color: inherit; + opacity: 0.8; + } + #tsd-search-results { + margin: 0; + padding: 0; + list-style: none; + flex: 1 1 auto; + display: flex; + flex-direction: column; + overflow-y: auto; + } + #tsd-search-results:not(:empty) { + margin-top: 0.5rem; + } + #tsd-search-results > li { + background-color: var(--color-background); + line-height: 1.5; + box-sizing: border-box; + border-radius: 4px; + } + #tsd-search-results > li:nth-child(even) { + background-color: var(--color-background-secondary); + } + #tsd-search-results > li:is(:hover, [aria-selected="true"]) { + background-color: var(--color-background-active); + color: var(--color-contrast-text); + } + /* It's important that this takes full size of parent `li`, to capture a click on `li` */ + #tsd-search-results > li > a { + display: flex; + align-items: center; + padding: 0.5rem 0.25rem; + box-sizing: border-box; + width: 100%; + } + #tsd-search-results > li > a > .text { + flex: 1 1 auto; + min-width: 0; + overflow-wrap: anywhere; + } + #tsd-search-results > li > a .parent { + color: var(--color-text-aside); + } + #tsd-search-results > li > a mark { + color: inherit; + background-color: inherit; + font-weight: bold; + } + #tsd-search-status { + flex: 1; + display: grid; + place-content: center; + text-align: center; + overflow-wrap: anywhere; + } + #tsd-search-status:not(:empty) { + min-height: 6rem; + } + + .tsd-signature { + margin: 0 0 1rem 0; + padding: 1rem 0.5rem; + border: 1px solid var(--color-accent); + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 14px; + overflow-x: auto; + } + + .tsd-signature-keyword { + color: var(--color-ts-keyword); + font-weight: normal; + } + + .tsd-signature-symbol { + color: var(--color-text-aside); + font-weight: normal; + } + + .tsd-signature-type { + font-style: italic; + font-weight: normal; + } + + .tsd-signatures { + padding: 0; + margin: 0 0 1em 0; + list-style-type: none; + } + .tsd-signatures .tsd-signature { + margin: 0; + border-color: var(--color-accent); + border-width: 1px 0; + transition: background-color 0.1s; + } + .tsd-signatures .tsd-index-signature:not(:last-child) { + margin-bottom: 1em; + } + .tsd-signatures .tsd-index-signature .tsd-signature { + border-width: 1px; + } + .tsd-description .tsd-signatures .tsd-signature { + border-width: 1px; + } + + ul.tsd-parameter-list, + ul.tsd-type-parameter-list { + list-style: square; + margin: 0; + padding-left: 20px; + } + ul.tsd-parameter-list > li.tsd-parameter-signature, + ul.tsd-type-parameter-list > li.tsd-parameter-signature { + list-style: none; + margin-left: -20px; + } + ul.tsd-parameter-list h5, + ul.tsd-type-parameter-list h5 { + font-size: 16px; + margin: 1em 0 0.5em 0; + } + .tsd-sources { + margin-top: 1rem; + font-size: 0.875em; + } + .tsd-sources a { + color: var(--color-text-aside); + text-decoration: underline; + } + .tsd-sources ul { + list-style: none; + padding: 0; + } + + .tsd-page-toolbar { + position: sticky; + z-index: 1; + top: 0; + left: 0; + width: 100%; + color: var(--color-text); + background: var(--color-background-secondary); + border-bottom: var(--dim-toolbar-border-bottom-width) + var(--color-accent) solid; + transition: transform 0.3s ease-in-out; + } + .tsd-page-toolbar a { + color: var(--color-text); + } + .tsd-toolbar-contents { + display: flex; + align-items: center; + height: var(--dim-toolbar-contents-height); + margin: 0 auto; + } + .tsd-toolbar-contents > .title { + font-weight: bold; + margin-right: auto; + } + #tsd-toolbar-links { + display: flex; + align-items: center; + gap: 1.5rem; + margin-right: 1rem; + } + + .tsd-widget { + box-sizing: border-box; + display: inline-block; + opacity: 0.8; + height: 2.5rem; + width: 2.5rem; + transition: opacity 0.1s, background-color 0.1s; + text-align: center; + cursor: pointer; + border: none; + background-color: transparent; + } + .tsd-widget:hover { + opacity: 0.9; + } + .tsd-widget:active { + opacity: 1; + background-color: var(--color-accent); + } + #tsd-toolbar-menu-trigger { + display: none; + } + + .tsd-member-summary-name { + display: inline-flex; + align-items: center; + padding: 0.25rem; + text-decoration: none; + } + + .tsd-anchor-icon { + display: inline-flex; + align-items: center; + margin-left: 0.5rem; + color: var(--color-text); + vertical-align: middle; + } + + .tsd-anchor-icon svg { + width: 1em; + height: 1em; + visibility: hidden; + } + + .tsd-member-summary-name:hover > .tsd-anchor-icon svg, + .tsd-anchor-link:hover > .tsd-anchor-icon svg, + .tsd-anchor-icon:focus-visible svg { + visibility: visible; + } + + .deprecated { + text-decoration: line-through !important; + } + + .warning { + padding: 1rem; + color: var(--color-warning-text); + background: var(--color-background-warning); + } + + .tsd-kind-project { + color: var(--color-ts-project); + } + .tsd-kind-module { + color: var(--color-ts-module); + } + .tsd-kind-namespace { + color: var(--color-ts-namespace); + } + .tsd-kind-enum { + color: var(--color-ts-enum); + } + .tsd-kind-enum-member { + color: var(--color-ts-enum-member); + } + .tsd-kind-variable { + color: var(--color-ts-variable); + } + .tsd-kind-function { + color: var(--color-ts-function); + } + .tsd-kind-class { + color: var(--color-ts-class); + } + .tsd-kind-interface { + color: var(--color-ts-interface); + } + .tsd-kind-constructor { + color: var(--color-ts-constructor); + } + .tsd-kind-property { + color: var(--color-ts-property); + } + .tsd-kind-method { + color: var(--color-ts-method); + } + .tsd-kind-reference { + color: var(--color-ts-reference); + } + .tsd-kind-call-signature { + color: var(--color-ts-call-signature); + } + .tsd-kind-index-signature { + color: var(--color-ts-index-signature); + } + .tsd-kind-constructor-signature { + color: var(--color-ts-constructor-signature); + } + .tsd-kind-parameter { + color: var(--color-ts-parameter); + } + .tsd-kind-type-parameter { + color: var(--color-ts-type-parameter); + } + .tsd-kind-accessor { + color: var(--color-ts-accessor); + } + .tsd-kind-get-signature { + color: var(--color-ts-get-signature); + } + .tsd-kind-set-signature { + color: var(--color-ts-set-signature); + } + .tsd-kind-type-alias { + color: var(--color-ts-type-alias); + } + + /* if we have a kind icon, don't color the text by kind */ + .tsd-kind-icon ~ span { + color: var(--color-text); + } + + /* mobile */ + @media (max-width: 769px) { + #tsd-toolbar-menu-trigger { + display: inline-block; + /* temporary fix to vertically align, for compatibility */ + line-height: 2.5; + } + #tsd-toolbar-links { + display: none; + } + + .container-main { + display: flex; + } + .col-content { + float: none; + max-width: 100%; + width: 100%; + } + .col-sidebar { + position: fixed !important; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + z-index: 1024; + top: 0 !important; + bottom: 0 !important; + left: auto !important; + right: 0 !important; + padding: 1.5rem 1.5rem 0 0; + width: 75vw; + visibility: hidden; + background-color: var(--color-background); + transform: translate(100%, 0); + } + .col-sidebar > *:last-child { + padding-bottom: 20px; + } + .overlay { + content: ""; + display: block; + position: fixed; + z-index: 1023; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + visibility: hidden; + } + + .to-has-menu .overlay { + animation: fade-in 0.4s; + } + + .to-has-menu .col-sidebar { + animation: pop-in-from-right 0.4s; + } + + .from-has-menu .overlay { + animation: fade-out 0.4s; + } + + .from-has-menu .col-sidebar { + animation: pop-out-to-right 0.4s; + } + + .has-menu body { + overflow: hidden; + } + .has-menu .overlay { + visibility: visible; + } + .has-menu .col-sidebar { + visibility: visible; + transform: translate(0, 0); + display: flex; + flex-direction: column; + gap: 1.5rem; + max-height: 100vh; + padding: 1rem 2rem; + } + .has-menu .tsd-navigation { + max-height: 100%; + } + .tsd-navigation .tsd-nav-link { + display: flex; + } + } + + /* one sidebar */ + @media (min-width: 770px) { + .container-main { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); + grid-template-areas: "sidebar content"; + --dim-container-main-margin-y: 2rem; + } + + .tsd-breadcrumb { + margin-top: 0; + } + + .col-sidebar { + grid-area: sidebar; + } + .col-content { + grid-area: content; + padding: 0 1rem; + } + } + @media (min-width: 770px) and (max-width: 1399px) { + .col-sidebar { + max-height: calc( + 100vh - var(--dim-header-height) - var(--dim-footer-height) - + 2 * var(--dim-container-main-margin-y) + ); + overflow: auto; + position: sticky; + top: calc( + var(--dim-header-height) + var(--dim-container-main-margin-y) + ); + } + .site-menu { + margin-top: 1rem; + } + } + + /* two sidebars */ + @media (min-width: 1200px) { + .container-main { + grid-template-columns: + minmax(0, 1fr) minmax(0, 2.5fr) minmax( + 0, + 20rem + ); + grid-template-areas: "sidebar content toc"; + } + + .col-sidebar { + display: contents; + } + + .page-menu { + grid-area: toc; + padding-left: 1rem; + } + .site-menu { + grid-area: sidebar; + } + + .site-menu { + margin-top: 0rem; + } + + .page-menu, + .site-menu { + max-height: calc( + 100vh - var(--dim-header-height) - var(--dim-footer-height) - + 2 * var(--dim-container-main-margin-y) + ); + overflow: auto; + position: sticky; + top: calc( + var(--dim-header-height) + var(--dim-container-main-margin-y) + ); + } + } +} diff --git a/docs/classes/HttpTransport.html b/docs/classes/HttpTransport.html new file mode 100644 index 0000000..0fb3117 --- /dev/null +++ b/docs/classes/HttpTransport.html @@ -0,0 +1,35 @@ +HttpTransport | QuestDB Node.js Client - v4.0.0

Class HttpTransport

HTTP transport implementation using Node.js built-in http/https modules.
+Supports both HTTP and HTTPS protocols with configurable authentication.

+

Hierarchy

  • HttpTransportBase
    • HttpTransport
Index

Constructors

Properties

secure: boolean
host: string
port: number
username: string
password: string
token: string
tlsVerify: boolean
tlsCA: Buffer
requestMinThroughput: number
requestTimeout: number
retryTimeout: number
log: Logger

Methods

  • HTTP transport does not require explicit connection establishment.

    +

    Returns Promise<boolean>

    Error indicating connect is not required for HTTP transport

    +
  • HTTP transport does not require explicit connection closure.

    +

    Returns Promise<void>

    Promise that resolves immediately

    +
  • Gets the default auto-flush row count for HTTP transport.

    +

    Returns number

    Default number of rows that trigger auto-flush

    +
  • Sends data to QuestDB using HTTP POST.

    +

    Parameters

    • data: Buffer

      Buffer containing the data to send

      +
    • retryBegin: number = -1

      Internal parameter for tracking retry start time

      +
    • retryInterval: number = -1

      Internal parameter for tracking retry intervals

      +

    Returns Promise<boolean>

    Promise resolving to true if data was sent successfully

    +

    Error if request fails after all retries or times out

    +
diff --git a/docs/classes/Sender.html b/docs/classes/Sender.html new file mode 100644 index 0000000..825cbe4 --- /dev/null +++ b/docs/classes/Sender.html @@ -0,0 +1,173 @@ +Sender | QuestDB Node.js Client - v4.0.0

Class Sender

The QuestDB client's API provides methods to connect to the database, ingest data, and close the connection.
+The client supports multiple transport protocols.

+

+Transport Options: +

    +
  • HTTP: Uses standard HTTP requests for data ingestion. Provides immediate feedback via HTTP response codes. +Recommended for most use cases due to superior error handling and debugging capabilities. Uses Undici library by default for high performance.
  • +
  • HTTPS: Secure HTTP transport with TLS encryption. Same benefits as HTTP but with encrypted communication. +Supports certificate validation and custom CA certificates.
  • +
  • TCP: Direct TCP connection, provides persistent connections. Uses JWK token-based authentication.
  • +
  • TCPS: Secure TCP transport with TLS encryption.
  • +
+

+

+The client supports authentication.
+Authentication details can be passed to the Sender in its configuration options.
+The client supports Basic username/password and Bearer token authentication methods when used with HTTP protocol, +and JWK token authentication when ingesting data via TCP.
+Please, note that authentication is enabled by default in QuestDB Enterprise only.
+Details on how to configure authentication in the open source version of +QuestDB: https://questdb.io/docs/reference/api/ilp/authenticate +

+

+The client also supports TLS encryption for both, HTTP and TCP transports to provide a secure connection.
+Please, note that the open source version of QuestDB does not support TLS, and requires an external reverse-proxy, +such as Nginx to enable encryption. +

+

+The client supports multiple protocol versions for data serialization. Protocol version 1 uses text-based +serialization, while version 2 uses binary encoding for doubles and supports array columns for improved +performance. The client can automatically negotiate the protocol version with the server when using HTTP/HTTPS +by setting the protocol_version to 'auto' (default behavior). +

+

+The client uses a buffer to store data. It automatically flushes the buffer by sending its content to the server. +Auto flushing can be disabled via configuration options to gain control over transactions. Initial and maximum +buffer sizes can also be set. +

+

+It is recommended that the Sender is created by using one of the static factory methods, +Sender.fromConfig(configString, extraOptions) or Sender.fromEnv(extraOptions). +If the Sender is created via its constructor, at least the SenderOptions configuration object should be +initialized from a configuration string to make sure that the parameters are validated.
+Detailed description of the Sender's configuration options can be found in +the SenderOptions documentation. +

+

+Transport Configuration Examples: +

    +
  • HTTP: Sender.fromConfig("http::addr=localhost:9000")
  • +
  • HTTPS with authentication: Sender.fromConfig("https::addr=localhost:9000;username=admin;password=secret")
  • +
  • TCP: Sender.fromConfig("tcp::addr=localhost:9009")
  • +
  • TCPS with authentication: Sender.fromConfig("tcps::addr=localhost:9009;username=user;token=private_key")
  • +
+

+

+HTTP Transport Implementation:
+By default, HTTP/HTTPS transport uses the high-performance Undici library for connection management and request handling. +For compatibility or specific requirements, you can enable the standard HTTP transport using Node.js built-in modules +by setting stdlib_http=on in the configuration string. The standard HTTP transport provides the same functionality +but uses Node.js http/https modules instead of Undici. +

+

+Extra options can be provided to the Sender in the extraOptions configuration object.
+A custom logging function and a custom HTTP(S) agent can be passed to the Sender in this object.
+The logger implementation provides the option to direct log messages to the same place where the host application's +log is saved. The default logger writes to the console.
+The custom HTTP(S) agent option becomes handy if there is a need to modify the default options set for the +HTTP(S) connections. A popular setting would be disabling persistent connections, in this case an agent can be +passed to the Sender with keepAlive set to false.
+For example: Sender.fromConfig(`http::addr=host:port`, { agent: new undici.Agent({ connect: { keepAlive: false } })})
+If no custom agent is configured, the Sender will use its own agent which overrides some default values +of undici.Agent. The Sender's own agent uses persistent connections with 1 minute idle timeout, pipelines requests default to 1. +

Index

Constructors

  • Creates an instance of Sender.

    +

    Parameters

    • options: SenderOptions

      Sender configuration object.
      +See SenderOptions documentation for detailed description of configuration options.

      +

    Returns Sender

Methods

  • Creates a Sender object by parsing the provided configuration string.

    +

    Parameters

    • configurationString: string

      Configuration string.

      +
    • OptionalextraOptions: ExtraOptions

      Optional extra configuration.

      +
        +
      • 'log' is a logging function used by the Sender. +Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
      • +
      • 'agent' is a custom http/https agent used by the Sender when http/https transport is used. +Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent.
      • +
      +

    Returns Promise<Sender>

    A Sender object initialized from the provided configuration string.

    +
  • Creates a Sender object by parsing the configuration string set in the QDB_CLIENT_CONF environment variable.

    +

    Parameters

    • OptionalextraOptions: ExtraOptions

      Optional extra configuration.

      +
        +
      • 'log' is a logging function used by the Sender. +Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
      • +
      • 'agent' is a custom http/https agent used by the Sender when http/https transport is used. +Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent.
      • +
      +

    Returns Promise<Sender>

    A Sender object initialized from the QDB_CLIENT_CONF environment variable.

    +
  • Resets the sender's buffer, data sitting in the buffer will be lost.
    +In other words it clears the buffer, and sets the writing position to the beginning of the buffer.

    +

    Returns Sender

    Returns with a reference to this sender.

    +
  • Creates a TCP connection to the database.

    +

    Returns Promise<boolean>

    Resolves to true if the client is connected.

    +
  • Sends the content of the sender's buffer to the database and compacts the buffer. +If the last row is not finished it stays in the sender's buffer.

    +

    Returns Promise<boolean>

    Resolves to true when there was data in the buffer to send, and it was sent successfully.

    +
  • Closes the connection to the database.
    +Data sitting in the Sender's buffer will be lost unless flush() is called before close().

    +

    Returns Promise<void>

  • Writes the table name into the buffer of the sender of the sender.

    +

    Parameters

    • table: string

      Table name.

      +

    Returns Sender

    Returns with a reference to this sender.

    +
  • Writes a symbol name and value into the buffer of the sender.
    +Use it to insert into SYMBOL columns.

    +

    Parameters

    • name: string

      Symbol name.

      +
    • value: unknown

      Symbol value, toString() is called to extract the actual symbol value from the parameter.

      +

    Returns Sender

    Returns with a reference to this sender.

    +
  • Writes a string column with its value into the buffer of the sender.
    +Use it to insert into VARCHAR and STRING columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: string

      Column value, accepts only string values.

      +

    Returns Sender

    Returns with a reference to this sender.

    +
  • Writes a boolean column with its value into the buffer of the sender.
    +Use it to insert into BOOLEAN columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: boolean

      Column value, accepts only boolean values.

      +

    Returns Sender

    Returns with a reference to this sender.

    +
  • Writes a 64-bit floating point value into the buffer of the sender.
    +Use it to insert into DOUBLE or FLOAT database columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number

      Column value, accepts only number values.

      +

    Returns Sender

    Returns with a reference to this sender.

    +
  • Writes an array column with its values into the buffer of the sender.

    +

    Parameters

    • name: string

      Column name

      +
    • value: unknown[]

      Array values to write (currently supports double arrays)

      +

    Returns Sender

    Returns with a reference to this sender.

    +

    Error if arrays are not supported by the buffer implementation, or array validation fails:

    +
      +
    • value is not an array
    • +
    • or the shape of the array is irregular: the length of sub-arrays are different
    • +
    • or the array is not homogeneous: its elements are not all the same type
    • +
    +
  • Writes a 64-bit signed integer into the buffer of the sender.
    +Use it to insert into LONG, INT, SHORT and BYTE columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number

      Column value, accepts only number values.

      +

    Returns Sender

    Returns with a reference to this sender.

    +

    Error if the value is not an integer

    +
  • Writes a timestamp column with its value into the buffer of the sender.
    +Use it to insert into TIMESTAMP columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number | bigint

      Epoch timestamp, accepts numbers or BigInts.

      +
    • Optionalunit: TimestampUnit = "us"

      Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.

      +

    Returns Sender

    Returns with a reference to this sender.

    +
  • Closes the row after writing the designated timestamp into the buffer of the sender.

    +

    Parameters

    • timestamp: number | bigint

      Designated epoch timestamp, accepts numbers or BigInts.

      +
    • Optionalunit: TimestampUnit = "us"

      Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.

      +

    Returns Promise<void>

  • Closes the row without writing designated timestamp into the buffer of the sender.
    +Designated timestamp will be populated by the server on this record.

    +

    Returns Promise<void>

diff --git a/docs/classes/SenderBufferV1.html b/docs/classes/SenderBufferV1.html new file mode 100644 index 0000000..d9a37a9 --- /dev/null +++ b/docs/classes/SenderBufferV1.html @@ -0,0 +1,81 @@ +SenderBufferV1 | QuestDB Node.js Client - v4.0.0

Class SenderBufferV1

Buffer implementation for protocol version 1.
+Sends floating point numbers in their text form.

+

Hierarchy

  • SenderBufferBase
    • SenderBufferV1
Index

Constructors

Properties

buffer: Buffer<ArrayBuffer>
position: number
log: Logger

Methods

  • Resets the buffer, data sitting in the buffer will be lost.
    +In other words it clears the buffer, and sets the writing position to the beginning of the buffer.

    +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Parameters

    • pos: number = ...

    Returns Buffer

    Returns a cropped buffer, or null if there is nothing to send.
    +The returned buffer is backed by this buffer instance, meaning the view can change as the buffer is mutated. +Used only in tests to assert the buffer's content.

    +
  • Parameters

    • pos: number = ...

    Returns Buffer

    Returns a cropped buffer ready to send to the server, or null if there is nothing to send.
    +The returned buffer is a copy of this buffer. +It also compacts the buffer.

    +
  • Writes the table name into the buffer.

    +

    Parameters

    • table: string

      Table name.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a symbol name and value into the buffer.
    +Use it to insert into SYMBOL columns.

    +

    Parameters

    • name: string

      Symbol name.

      +
    • value: unknown

      Symbol value, toString() is called to extract the actual symbol value from the parameter.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a string column with its value into the buffer.
    +Use it to insert into VARCHAR and STRING columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: string

      Column value, accepts only string values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a boolean column with its value into the buffer.
    +Use it to insert into BOOLEAN columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: boolean

      Column value, accepts only boolean values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a 64-bit signed integer into the buffer.
    +Use it to insert into LONG, INT, SHORT and BYTE columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number

      Column value, accepts only number values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +

    Error if the value is not an integer

    +
  • Writes a timestamp column with its value into the buffer.
    +Use it to insert into TIMESTAMP columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number | bigint

      Epoch timestamp, accepts numbers or BigInts.

      +
    • Optionalunit: TimestampUnit = "us"

      Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Closes the row after writing the designated timestamp into the buffer.

    +

    Parameters

    • timestamp: number | bigint

      Designated epoch timestamp, accepts numbers or BigInts.

      +
    • Optionalunit: TimestampUnit = "us"

      Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.

      +

    Returns void

  • Closes the row without writing designated timestamp into the buffer.
    +Designated timestamp will be populated by the server on this record.

    +

    Returns void

  • Returns the current position of the buffer.
    +New data will be written into the buffer starting from this position.

    +

    Returns number

  • Checks if the buffer has sufficient capacity for additional data and resizes if needed.

    +

    Parameters

    • data: string[]

      Array of strings to calculate the required capacity for

      +
    • base: number = 0

      Base number of bytes to add to the calculation

      +

    Returns void

  • Writes a 64-bit floating point value into the buffer using v1 serialization (text format).
    +Use it to insert into DOUBLE or FLOAT database columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number

      Column value, accepts only number values.

      +

    Returns SenderBuffer

    Returns with a reference to this sender.

    +
diff --git a/docs/classes/SenderBufferV2.html b/docs/classes/SenderBufferV2.html new file mode 100644 index 0000000..710c36d --- /dev/null +++ b/docs/classes/SenderBufferV2.html @@ -0,0 +1,89 @@ +SenderBufferV2 | QuestDB Node.js Client - v4.0.0

Class SenderBufferV2

Buffer implementation for protocol version 2.
+Sends floating point numbers in binary form, and provides support for arrays.

+

Hierarchy

  • SenderBufferBase
    • SenderBufferV2
Index

Constructors

Properties

buffer: Buffer<ArrayBuffer>
position: number
log: Logger

Methods

  • Resets the buffer, data sitting in the buffer will be lost.
    +In other words it clears the buffer, and sets the writing position to the beginning of the buffer.

    +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Parameters

    • pos: number = ...

    Returns Buffer

    Returns a cropped buffer, or null if there is nothing to send.
    +The returned buffer is backed by this buffer instance, meaning the view can change as the buffer is mutated. +Used only in tests to assert the buffer's content.

    +
  • Parameters

    • pos: number = ...

    Returns Buffer

    Returns a cropped buffer ready to send to the server, or null if there is nothing to send.
    +The returned buffer is a copy of this buffer. +It also compacts the buffer.

    +
  • Writes the table name into the buffer.

    +

    Parameters

    • table: string

      Table name.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a symbol name and value into the buffer.
    +Use it to insert into SYMBOL columns.

    +

    Parameters

    • name: string

      Symbol name.

      +
    • value: unknown

      Symbol value, toString() is called to extract the actual symbol value from the parameter.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a string column with its value into the buffer.
    +Use it to insert into VARCHAR and STRING columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: string

      Column value, accepts only string values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a boolean column with its value into the buffer.
    +Use it to insert into BOOLEAN columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: boolean

      Column value, accepts only boolean values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a 64-bit signed integer into the buffer.
    +Use it to insert into LONG, INT, SHORT and BYTE columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number

      Column value, accepts only number values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +

    Error if the value is not an integer

    +
  • Writes a timestamp column with its value into the buffer.
    +Use it to insert into TIMESTAMP columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number | bigint

      Epoch timestamp, accepts numbers or BigInts.

      +
    • Optionalunit: TimestampUnit = "us"

      Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Closes the row after writing the designated timestamp into the buffer.

    +

    Parameters

    • timestamp: number | bigint

      Designated epoch timestamp, accepts numbers or BigInts.

      +
    • Optionalunit: TimestampUnit = "us"

      Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.

      +

    Returns void

  • Closes the row without writing designated timestamp into the buffer.
    +Designated timestamp will be populated by the server on this record.

    +

    Returns void

  • Returns the current position of the buffer.
    +New data will be written into the buffer starting from this position.

    +

    Returns number

  • Checks if the buffer has sufficient capacity for additional data and resizes if needed.

    +

    Parameters

    • data: string[]

      Array of strings to calculate the required capacity for

      +
    • base: number = 0

      Base number of bytes to add to the calculation

      +

    Returns void

  • Writes a 64-bit floating point value into the buffer using v2 serialization (binary format).
    +Use it to insert into DOUBLE or FLOAT database columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number

      Column value, accepts only number values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Write an array column with its values into the buffer using v2 format.

    +

    Parameters

    • name: string

      Column name

      +
    • value: unknown[]

      Array values to write (currently supports double arrays)

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +

    Error if array validation fails:

    +
      +
    • value is not an array
    • +
    • or the shape of the array is irregular: the length of sub-arrays are different
    • +
    • or the array is not homogeneous: its elements are not all the same type
    • +
    +
diff --git a/docs/classes/TcpTransport.html b/docs/classes/TcpTransport.html new file mode 100644 index 0000000..b4ed030 --- /dev/null +++ b/docs/classes/TcpTransport.html @@ -0,0 +1,21 @@ +TcpTransport | QuestDB Node.js Client - v4.0.0

Class TcpTransport

TCP transport implementation.
+Supports both plain TCP or secure TLS-encrypted connections with configurable JWK token authentication.

+

Implements

Index

Constructors

Methods

  • Creates a TCP connection to the database.

    +

    Returns Promise<boolean>

    Promise resolving to true if the connection is established successfully

    +

    Error if connection fails or authentication is rejected

    +
  • Sends data over the established TCP connection.

    +

    Parameters

    • data: Buffer

      Buffer containing the data to send

      +

    Returns Promise<boolean>

    Promise resolving to true if data was sent successfully

    +

    Error if the data could not be written to the socket

    +
diff --git a/docs/classes/UndiciTransport.html b/docs/classes/UndiciTransport.html new file mode 100644 index 0000000..4b4e47b --- /dev/null +++ b/docs/classes/UndiciTransport.html @@ -0,0 +1,34 @@ +UndiciTransport | QuestDB Node.js Client - v4.0.0

Class UndiciTransport

HTTP transport implementation using the Undici library.
+Provides high-performance HTTP requests with connection pooling and retry logic.
+Supports both HTTP and HTTPS protocols with configurable authentication.

+

Hierarchy

  • HttpTransportBase
    • UndiciTransport
Index

Constructors

Properties

secure: boolean
host: string
port: number
username: string
password: string
token: string
tlsVerify: boolean
tlsCA: Buffer
requestMinThroughput: number
requestTimeout: number
retryTimeout: number
log: Logger

Methods

  • HTTP transport does not require explicit connection establishment.

    +

    Returns Promise<boolean>

    Error indicating connect is not required for HTTP transport

    +
  • HTTP transport does not require explicit connection closure.

    +

    Returns Promise<void>

    Promise that resolves immediately

    +
  • Gets the default auto-flush row count for HTTP transport.

    +

    Returns number

    Default number of rows that trigger auto-flush

    +
  • Sends data to QuestDB using HTTP POST.

    +

    Parameters

    • data: Buffer

      Buffer containing the data to send

      +

    Returns Promise<boolean>

    Promise resolving to true if data was sent successfully

    +

    Error if request fails after all retries or times out

    +
diff --git a/docs/fonts/OpenSans-Bold-webfont.eot b/docs/fonts/OpenSans-Bold-webfont.eot deleted file mode 100644 index 5d20d91..0000000 Binary files a/docs/fonts/OpenSans-Bold-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Bold-webfont.svg b/docs/fonts/OpenSans-Bold-webfont.svg deleted file mode 100644 index 3ed7be4..0000000 --- a/docs/fonts/OpenSans-Bold-webfont.svg +++ /dev/null @@ -1,1830 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Bold-webfont.woff b/docs/fonts/OpenSans-Bold-webfont.woff deleted file mode 100644 index 1205787..0000000 Binary files a/docs/fonts/OpenSans-Bold-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.eot b/docs/fonts/OpenSans-BoldItalic-webfont.eot deleted file mode 100644 index 1f639a1..0000000 Binary files a/docs/fonts/OpenSans-BoldItalic-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.svg b/docs/fonts/OpenSans-BoldItalic-webfont.svg deleted file mode 100644 index 6a2607b..0000000 --- a/docs/fonts/OpenSans-BoldItalic-webfont.svg +++ /dev/null @@ -1,1830 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.woff b/docs/fonts/OpenSans-BoldItalic-webfont.woff deleted file mode 100644 index ed760c0..0000000 Binary files a/docs/fonts/OpenSans-BoldItalic-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-Italic-webfont.eot b/docs/fonts/OpenSans-Italic-webfont.eot deleted file mode 100644 index 0c8a0ae..0000000 Binary files a/docs/fonts/OpenSans-Italic-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Italic-webfont.svg b/docs/fonts/OpenSans-Italic-webfont.svg deleted file mode 100644 index e1075dc..0000000 --- a/docs/fonts/OpenSans-Italic-webfont.svg +++ /dev/null @@ -1,1830 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Italic-webfont.woff b/docs/fonts/OpenSans-Italic-webfont.woff deleted file mode 100644 index ff652e6..0000000 Binary files a/docs/fonts/OpenSans-Italic-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-Light-webfont.eot b/docs/fonts/OpenSans-Light-webfont.eot deleted file mode 100644 index 1486840..0000000 Binary files a/docs/fonts/OpenSans-Light-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Light-webfont.svg b/docs/fonts/OpenSans-Light-webfont.svg deleted file mode 100644 index 11a472c..0000000 --- a/docs/fonts/OpenSans-Light-webfont.svg +++ /dev/null @@ -1,1831 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Light-webfont.woff b/docs/fonts/OpenSans-Light-webfont.woff deleted file mode 100644 index e786074..0000000 Binary files a/docs/fonts/OpenSans-Light-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.eot b/docs/fonts/OpenSans-LightItalic-webfont.eot deleted file mode 100644 index 8f44592..0000000 Binary files a/docs/fonts/OpenSans-LightItalic-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.svg b/docs/fonts/OpenSans-LightItalic-webfont.svg deleted file mode 100644 index 431d7e3..0000000 --- a/docs/fonts/OpenSans-LightItalic-webfont.svg +++ /dev/null @@ -1,1835 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-LightItalic-webfont.woff b/docs/fonts/OpenSans-LightItalic-webfont.woff deleted file mode 100644 index 43e8b9e..0000000 Binary files a/docs/fonts/OpenSans-LightItalic-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-Regular-webfont.eot b/docs/fonts/OpenSans-Regular-webfont.eot deleted file mode 100644 index 6bbc3cf..0000000 Binary files a/docs/fonts/OpenSans-Regular-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Regular-webfont.svg b/docs/fonts/OpenSans-Regular-webfont.svg deleted file mode 100644 index 25a3952..0000000 --- a/docs/fonts/OpenSans-Regular-webfont.svg +++ /dev/null @@ -1,1831 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Regular-webfont.woff b/docs/fonts/OpenSans-Regular-webfont.woff deleted file mode 100644 index e231183..0000000 Binary files a/docs/fonts/OpenSans-Regular-webfont.woff and /dev/null differ diff --git a/docs/global.html b/docs/global.html deleted file mode 100644 index b978d88..0000000 --- a/docs/global.html +++ /dev/null @@ -1,2328 +0,0 @@ - - - - - JSDoc: Global - - - - - - - - - - -
- -

Global

- - - - - - -
- -
- -

- - -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - - - - - - - - - -

Members

- - - -

(constant) DEFAULT_HTTP_AGENT_CONFIG

- - - - -
- Default configuration for HTTP agents. -- Persistent connections with 1 minute idle timeout -- Maximum of 256 open connections (matching server default) -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(constant) DEFAULT_HTTP_OPTIONS

- - - - -
- Default HTTP options for the Undici agent. -Configures keep-alive connections with 60-second timeout and single request pipelining. -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - -

Methods

- - - - - - - -

createBuffer(options)

- - - - - - -
- Factory function to create a SenderBuffer instance based on the protocol version. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - Sender configuration object.
-See SenderOptions documentation for detailed description of configuration options.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if protocol version is not specified or is unsupported - -
- - - - - -
Returns:
- - -
- A SenderBuffer instance appropriate for the specified protocol version -
- - - - - - - - - - - - - - - -

createTransport(options)

- - - - - - -
- Factory function to create appropriate transport instance based on configuration. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -SenderOptions - - - - Sender configuration options including protocol and connection details
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if protocol or host options are missing or invalid - -
- - - - - -
Returns:
- - -
- Transport instance appropriate for the specified protocol -
- - - - - - - - - - - - - - - -

(async) fetchJson(url, agent, timeout)

- - - - - - -
- Fetches JSON data from a URL. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
url - - -string - - - - The URL to fetch from
agent - - -Agent - - - - HTTP agent to be used for the request
timeout - - -number - - - - Request timeout, query will be aborted if not finished in time
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if the request fails or returns a non-OK status - -
- - - - - -
Returns:
- - -
- Promise resolving to the parsed JSON data -
- - - - - - - - - - - - - - - -

getDimensions(data)

- - - - - - -
- Analyzes the dimensions of a nested array structure. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -unknown - - - - The array to analyze
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if any dimension has zero length - -
- - - - - -
Returns:
- - -
- Array of dimension sizes at each nesting level -
- - - - - - - - - - - - - - - -

isBoolean(value)

- - - - - - -
- Type guard to check if a value is a boolean. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
value - - -unknown - - - - The value to check
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- True if the value is a boolean, false otherwise -
- - - - - - - - - - - - - - - -

isInteger(value, lowerBound)

- - - - - - -
- Type guard to check if a value is an integer within specified bounds. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
value - - -unknown - - - - The value to check
lowerBound - - -number - - - - The minimum allowed value (inclusive)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- True if the value is an integer >= lowerBound, false otherwise -
- - - - - - - - - - - - - - - -

log(level, message)

- - - - - - -
- Simple logger to write log messages to the console.
-Supported logging levels are `error`, `warn`, `info` and `debug`.
-Throws an error if logging level is invalid. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
level - - -'error' -| - -'warn' -| - -'info' -| - -'debug' - - - - The log level for the message
message - - -string -| - -Error - - - - The message to log, either a string or Error object
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

timestampToMicros(timestamp, unit)

- - - - - - -
- Converts a timestamp from the specified unit to microseconds. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
timestamp - - -bigint - - - - The timestamp value as a bigint
unit - - -TimestampUnit - - - - The source timestamp unit
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if the timestamp unit is unknown - -
- - - - - -
Returns:
- - -
- The timestamp converted to microseconds -
- - - - - - - - - - - - - - - -

timestampToNanos(timestamp, unit)

- - - - - - -
- Converts a timestamp from the specified unit to nanoseconds. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
timestamp - - -bigint - - - - The timestamp value as a bigint
unit - - -TimestampUnit - - - - The source timestamp unit
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if the timestamp unit is unknown - -
- - - - - -
Returns:
- - -
- The timestamp converted to nanoseconds -
- - - - - - - - - - - - - - - -

validateArray(data, dimensions)

- - - - - - -
- Validates an array structure.
-Validation fails if: -- data is not an array -- the array is irregular: the length of its sub-arrays are different -- the array is not homogenous: the array contains mixed types -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -Array.<unknown> - - - - The array to validate
dimensions - - -Array.<number> - - - - The shape of the array
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if the validation fails - -
- - - - - -
Returns:
- - -
- The primitive type of the array's elements -
- - - - - - - - - - - - - - - -

validateColumnName(name, maxNameLength)

- - - - - - -
- Validates a column name. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - The column name to validate.
maxNameLength - - -number - - - - The maximum length of column names.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if column name is invalid. - -
- - - - - - - - - - - - - - - - -

validateTableName(name, maxNameLength)

- - - - - - -
- Validates a table name. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - The table name to validate.
maxNameLength - - -number - - - - The maximum length of table names.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - -
Throws:
- - - -
- - Error if table name is invalid. - -
- - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/hierarchy.html b/docs/hierarchy.html new file mode 100644 index 0000000..9f04f5c --- /dev/null +++ b/docs/hierarchy.html @@ -0,0 +1 @@ +QuestDB Node.js Client - v4.0.0

QuestDB Node.js Client - v4.0.0

Hierarchy Summary

diff --git a/docs/index.html b/docs/index.html index c09ab1e..c98616d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,305 +1,56 @@ - - - - - JSDoc: Home +QuestDB Node.js Client - v4.0.0

QuestDB Node.js Client - v4.0.0

# With npm
npm i -s @questdb/nodejs-client

# With yarn
yarn add @questdb/nodejs-client

# With pnpm
pnpm add @questdb/nodejs-client +
- - - - - - - - - -
- -

Home

- - - - - - - - -

- - - - - - - - - - - - - - - -
-

QuestDB Node.js Client

-

Requirements

-

The client requires Node.js v20 or newer version.

-

Installation

-
# With npm
-npm i -s @questdb/nodejs-client
-
-# With yarn
-yarn add @questdb/nodejs-client
-
-# With pnpm
-pnpm add @questdb/nodejs-client
-
-

Compatibility table

- +
- - + + - - + + - - + +
QuestDB client versionNode.js versionHTTP AgentSupported Node.js versionsDefault HTTP Agent
^4.0.0>=v20.X.XUndici Agentv20 and aboveUndici Http Agent
^3.0.0<v20.X.XHttp Agentv16 and aboveStandard Http Agent
-

Configuration options

-

Detailed description of the client's configuration options can be found in -the SenderOptions documentation.

-

Examples

-

The examples below demonstrate how to use the client.
-For more details, please, check the Sender's documentation.

-

Basic API usage

-
import { Sender } from "@questdb/nodejs-client";
-
-async function run() {
-    // create a sender
-    const sender = await Sender.fromConfig('http::addr=localhost:9000');
-
-    // order book snapshots
-    const orderBooks = [
-        {
-            symbol: 'BTC-USD',
-            exchange: 'COINBASE',
-            timestamp: Date.now(),
-            bidPrices: [50100.25, 50100.20, 50100.15, 50100.10, 50100.05],
-            bidSizes: [0.5, 1.2, 2.1, 0.8, 3.5],
-            askPrices: [50100.30, 50100.35, 50100.40, 50100.45, 50100.50],
-            askSizes: [0.6, 1.5, 1.8, 2.2, 4.0]
-        },
-        {
-            symbol: 'ETH-USD',
-            exchange: 'COINBASE',
-            timestamp: Date.now(),
-            bidPrices: [2850.50, 2850.45, 2850.40, 2850.35, 2850.30],
-            bidSizes: [5.0, 8.2, 12.5, 6.8, 15.0],
-            askPrices: [2850.55, 2850.60, 2850.65, 2850.70, 2850.75],
-            askSizes: [4.5, 7.8, 10.2, 8.5, 20.0]
-        }
-    ];
-
-    try {
-        // add rows to the buffer of the sender
-        for (const orderBook of orderBooks) {
-            await sender
-                .table('order_book_l2')
-                .symbol('symbol', orderBook.symbol)
-                .symbol('exchange', orderBook.exchange)
-                .arrayColumn('bid_prices', orderBook.bidPrices)
-                .arrayColumn('bid_sizes', orderBook.bidSizes)
-                .arrayColumn('ask_prices', orderBook.askPrices)
-                .arrayColumn('ask_sizes', orderBook.askSizes)
-                .at(orderBook.timestamp, 'ms');
-        }
-
-        // flush the buffer of the sender, sending the data to QuestDB
-        // the buffer is cleared after the data is sent, and the sender is ready to accept new data
-        await sender.flush();
-    } finally {
-      // close the connection after all rows ingested
-      await sender.close();
-    }
-}
-
-run().then(console.log).catch(console.error);
-
-

Authentication and secure connection

-

Username and password authentication

-
import { Sender } from "@questdb/nodejs-client";
-
-async function run() {
-  // create a sender using HTTPS protocol with username and password authentication
-  const sender = Sender.fromConfig(
-    "https::addr=127.0.0.1:9000;username=admin;password=quest",
-  );
-
-  // send the data over the authenticated and secure connection
-  await sender
-    .table("trades")
-    .symbol("symbol", "ETH-USD")
-    .symbol("side", "sell")
-    .floatColumn("price", 2615.54)
-    .floatColumn("amount", 0.00044)
-    .at(Date.now(), "ms");
-  await sender.flush();
-
-  // close the connection after all rows ingested
-  await sender.close();
-}
-
-run().catch(console.error);
-
-

Token authentication

-
import { Sender } from "@questdb/nodejs-client";
-
-async function run(): Promise<void> {
-  // create a sender using HTTPS protocol with bearer token authentication
-  const sender: Sender = Sender.fromConfig(
-    "https::addr=127.0.0.1:9000;token=Xyvd3er6GF87ysaHk",
-  );
-
-  // send the data over the authenticated and secure connection
-  await sender
-    .table("trades")
-    .symbol("symbol", "ETH-USD")
-    .symbol("side", "sell")
-    .floatColumn("price", 2615.54)
-    .floatColumn("amount", 0.00044)
-    .at(Date.now(), "ms");
-  await sender.flush();
-
-  // close the connection after all rows ingested
-  await sender.close();
-}
-
-run().catch(console.error);
-
-

Worker threads example

-
import { Sender } from "@questdb/nodejs-client";
-const {
-  Worker,
-  isMainThread,
-  parentPort,
-  workerData,
-} = require("worker_threads");
-
-// fake venue
-// generates random prices and amounts for a ticker for max 5 seconds, then the feed closes
-function* venue(ticker) {
-  let end = false;
-  setTimeout(() => {
-    end = true;
-  }, rndInt(5000));
-  while (!end) {
-    yield { ticker, price: Math.random(), amount: Math.random() };
-  }
-}
-
-// market data feed simulator
-// uses the fake venue to deliver price and amount updates to the feed handler (onTick() callback)
-async function subscribe(ticker, onTick) {
-  const feed = venue(workerData.ticker);
-  let tick;
-  while ((tick = feed.next().value)) {
-    await onTick(tick);
-    await sleep(rndInt(30));
-  }
-}
-
-async function run() {
-  if (isMainThread) {
-    const tickers = ["ETH-USD", "BTC-USD", "SOL-USD", "DOGE-USD"];
-    // main thread to start a worker thread for each ticker
-    for (let ticker of tickers) {
-      const worker = new Worker(__filename, { workerData: { ticker: ticker } })
-        .on("error", (err) => {
-          throw err;
-        })
-        .on("exit", () => {
-          console.log(`${ticker} thread exiting...`);
-        })
-        .on("message", (msg) => {
-          console.log(`Ingested ${msg.count} prices for ticker ${msg.ticker}`);
-        });
-    }
-  } else {
-    // it is important that each worker has a dedicated sender object
-    // threads cannot share the sender because they would write into the same buffer
-    const sender = Sender.fromConfig("http::addr=127.0.0.1:9000");
-
-    // subscribe for the market data of the ticker assigned to the worker
-    // ingest each price update into the database using the sender
-    let count = 0;
-    await subscribe(workerData.ticker, async (tick) => {
-      await sender
-        .table("trades")
-        .symbol("symbol", tick.ticker)
-        .symbol("side", "sell")
-        .floatColumn("price", tick.price)
-        .floatColumn("amount", tick.amount)
-        .at(Date.now(), "ms");
-      await sender.flush();
-      count++;
-    });
-
-    // let the main thread know how many prices were ingested
-    parentPort.postMessage({ ticker: workerData.ticker, count });
-
-    // close the connection to the database
-    await sender.close();
-  }
-}
-
-function sleep(ms) {
-  return new Promise((resolve) => setTimeout(resolve, ms));
-}
-
-function rndInt(limit) {
-  return Math.floor(Math.random() * limit + 1);
-}
-
-run().then(console.log).catch(console.error);
-
-

Community

-

If you need help, have additional questions or want to provide feedback, you +

The current version of the client requires Node.js v20 or newer version. +Versions up to and including 3.0.0 are compatible with Node.js v16 and above.

+

The Undici HTTP agent was introduced in 4.0.0, and it is the default HTTP transport. +The standard HTTP/HTTPS modules of Node.js are still supported for backwards compatibility. +Use the stdlib_http option to switch to the standard HTTP/HTTPS modules.

+

Detailed description of the client's configuration options can be found in +the SenderOptions documentation.

+

The examples below demonstrate how to use the client.
+For more details, please, check the Sender's documentation.

+
import { Sender } from "@questdb/nodejs-client";

async function run() {
// create a sender using HTTP protocol
const sender = await Sender.fromConfig("http::addr=127.0.0.1:9000");

// add rows to the buffer of the sender
await sender
.table("trades")
.symbol("symbol", "BTC-USD")
.symbol("side", "sell")
.floatColumn("price", 39269.98)
.floatColumn("amount", 0.011)
.at(Date.now(), "ms");

// flush the buffer of the sender, sending the data to QuestDB
// the buffer is cleared after the data is sent, and the sender is ready to accept new data
await sender.flush();

// close the connection after all rows ingested
// unflushed data will be lost
await sender.close();
}

run().then(console.log).catch(console.error); +
+ +
import { Sender } from "@questdb/nodejs-client";

async function run() {
// authentication details
const USER = "admin";
const PWD = "quest";

// pass the authentication details to the sender
// for secure connection use 'https' protocol instead of 'http'
const sender = await Sender.fromConfig(
`http::addr=127.0.0.1:9000;username=${USER};password=${PWD}`
);

// add rows to the buffer of the sender
await sender
.table("trades")
.symbol("symbol", "ETH-USD")
.symbol("side", "sell")
.floatColumn("price", 2615.54)
.floatColumn("amount", 0.00044)
.at(Date.now(), "ms");

// flush the buffer of the sender, sending the data to QuestDB
await sender.flush();

// close the connection after all rows ingested
await sender.close();
}

run().catch(console.error); +
+ +
import { Sender } from "@questdb/nodejs-client";

async function run() {
// authentication details
const TOKEN = "Xyvd3er6GF87ysaHk";

// pass the authentication details to the sender
// for secure connection use 'https' protocol instead of 'http'
const sender = await Sender.fromConfig(
`http::addr=127.0.0.1:9000;token=${TOKEN}`
);

// add rows to the buffer of the sender
await sender
.table("trades")
.symbol("symbol", "ETH-USD")
.symbol("side", "sell")
.floatColumn("price", 2615.54)
.floatColumn("amount", 0.00044)
.at(Date.now(), "ms");

// flush the buffer of the sender, sending the data to QuestDB
await sender.flush();

// close the connection after all rows ingested
await sender.close();
}

run().catch(console.error); +
+ +
import { Sender } from "@questdb/nodejs-client";

async function run() {
// authentication details
const CLIENT_ID = "admin";
const PRIVATE_KEY = "ZRxmCOQBpZoj2fZ-lEtqzVDkCre_ouF3ePpaQNDwoQk";

// pass the authentication details to the sender
const sender = await Sender.fromConfig(
`tcp::addr=127.0.0.1:9009;username=${CLIENT_ID};token=${PRIVATE_KEY}`
);
await sender.connect();

// add rows to the buffer of the sender
await sender
.table("trades")
.symbol("symbol", "BTC-USD")
.symbol("side", "sell")
.floatColumn("price", 39269.98)
.floatColumn("amount", 0.001)
.at(Date.now(), "ms");

// flush the buffer of the sender, sending the data to QuestDB
await sender.flush();

// close the connection after all rows ingested
await sender.close();
}

run().catch(console.error); +
+ +
import { Sender } from "@questdb/nodejs-client";

async function run() {
// create a sender
const sender = await Sender.fromConfig('http::addr=localhost:9000');

// order book snapshots to ingest
const orderBooks = [
{
symbol: 'BTC-USD',
exchange: 'Coinbase',
timestamp: Date.now(),
bidPrices: [50100.25, 50100.20, 50100.15, 50100.10, 50100.05],
bidSizes: [0.5, 1.2, 2.1, 0.8, 3.5],
askPrices: [50100.30, 50100.35, 50100.40, 50100.45, 50100.50],
askSizes: [0.6, 1.5, 1.8, 2.2, 4.0]
},
{
symbol: 'ETH-USD',
exchange: 'Coinbase',
timestamp: Date.now(),
bidPrices: [2850.50, 2850.45, 2850.40, 2850.35, 2850.30],
bidSizes: [5.0, 8.2, 12.5, 6.8, 15.0],
askPrices: [2850.55, 2850.60, 2850.65, 2850.70, 2850.75],
askSizes: [4.5, 7.8, 10.2, 8.5, 20.0]
}
];

try {
// add rows to the buffer of the sender
for (const orderBook of orderBooks) {
await sender
.table('order_book_l2')
.symbol('symbol', orderBook.symbol)
.symbol('exchange', orderBook.exchange)
.arrayColumn('bid_prices', orderBook.bidPrices)
.arrayColumn('bid_sizes', orderBook.bidSizes)
.arrayColumn('ask_prices', orderBook.askPrices)
.arrayColumn('ask_sizes', orderBook.askSizes)
.at(orderBook.timestamp, 'ms');
}

// flush the buffer of the sender, sending the data to QuestDB
// the buffer is cleared after the data is sent, and the sender is ready to accept new data
await sender.flush();
} finally {
// close the connection after all rows ingested
await sender.close();
}
}

run().then(console.log).catch(console.error); +
+ +
import { Sender } from "@questdb/nodejs-client";
import { Worker, isMainThread, parentPort, workerData } from "worker_threads";

// fake venue
// generates random prices and amounts for a ticker for max 5 seconds, then the feed closes
function* venue(ticker) {
let end = false;
setTimeout(() => {
end = true;
}, rndInt(5000));
while (!end) {
yield { ticker, price: Math.random(), amount: Math.random() };
}
}

// market data feed simulator
// uses the fake venue to deliver price and amount updates to the feed handler (onTick() callback)
async function subscribe(ticker, onTick) {
const feed = venue(workerData.ticker);
let tick;
while ((tick = feed.next().value)) {
await onTick(tick);
await sleep(rndInt(30));
}
}

async function run() {
if (isMainThread) {
const tickers = ["ETH-USD", "BTC-USD", "SOL-USD", "DOGE-USD"];
// main thread to start a worker thread for each ticker
for (let ticker of tickers) {
new Worker(__filename, { workerData: { ticker: ticker } })
.on("error", (err) => {
throw err;
})
.on("exit", () => {
console.log(`${ticker} thread exiting...`);
})
.on("message", (msg) => {
console.log(`Ingested ${msg.count} prices for ticker ${msg.ticker}`);
});
}
} else {
// it is important that each worker has a dedicated sender object
// threads cannot share the sender because they would write into the same buffer
const sender = await Sender.fromConfig("http::addr=127.0.0.1:9000");

// subscribe for the market data of the ticker assigned to the worker
// ingest each price update into the database using the sender
let count = 0;
await subscribe(workerData.ticker, async (tick) => {
await sender
.table("trades")
.symbol("symbol", tick.ticker)
.symbol("side", "sell")
.floatColumn("price", tick.price)
.floatColumn("amount", tick.amount)
.at(Date.now(), "ms");
await sender.flush();
count++;
});

// let the main thread know how many prices were ingested
parentPort.postMessage({ ticker: workerData.ticker, count });

// close the connection to the database
await sender.close();
}
}

function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

function rndInt(limit: number) {
return Math.floor(Math.random() * limit + 1);
}

run().then(console.log).catch(console.error); +
+ +

If you need help, have additional questions or want to provide feedback, you may find us on our Community Forum.

You can also sign up to our mailing list -to get notified of new releases.

-
- - - - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - \ No newline at end of file +to get notified of new releases.

+
diff --git a/docs/index.js.html b/docs/index.js.html deleted file mode 100644 index 1f0c870..0000000 --- a/docs/index.js.html +++ /dev/null @@ -1,2229 +0,0 @@ - - - - - JSDoc: Source: index.js - - - - - - - - - - -
- -

Source: index.js

- - - - - - -
-
-
var node_fs = require('node:fs');
-var undici = require('undici');
-var http = require('http');
-var https = require('https');
-var node_buffer = require('node:buffer');
-var net = require('node:net');
-var tls = require('node:tls');
-var crypto = require('node:crypto');
-
-function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
-
-var http__default = /*#__PURE__*/_interopDefault(http);
-var https__default = /*#__PURE__*/_interopDefault(https);
-var net__default = /*#__PURE__*/_interopDefault(net);
-var tls__default = /*#__PURE__*/_interopDefault(tls);
-var crypto__default = /*#__PURE__*/_interopDefault(crypto);
-
-// Log level configuration with console methods and criticality levels. <br>
-// Higher criticality values indicate more important messages.
-const LOG_LEVELS = {
-    error: {
-        log: console.error,
-        criticality: 3
-    },
-    warn: {
-        log: console.warn,
-        criticality: 2
-    },
-    info: {
-        log: console.info,
-        criticality: 1
-    },
-    debug: {
-        log: console.debug,
-        criticality: 0
-    }
-};
-// Default logging criticality level. Messages with criticality below this level are ignored.
-const DEFAULT_CRITICALITY = LOG_LEVELS.info.criticality;
-/**
- * Simple logger to write log messages to the console. <br>
- * Supported logging levels are `error`, `warn`, `info` and `debug`. <br>
- * Throws an error if logging level is invalid.
- *
- * @param {'error'|'warn'|'info'|'debug'} level - The log level for the message
- * @param {string | Error} message - The message to log, either a string or Error object
- */ function log(level, message) {
-    const logLevel = LOG_LEVELS[level];
-    if (!logLevel) {
-        throw new Error(`Invalid log level: '${level}'`);
-    }
-    if (logLevel.criticality >= DEFAULT_CRITICALITY) {
-        logLevel.log(message);
-    }
-}
-
-/**
- * Type guard to check if a value is a boolean.
- * @param {unknown} value - The value to check
- * @returns True if the value is a boolean, false otherwise
- */ function isBoolean(value) {
-    return typeof value === "boolean";
-}
-/**
- * Type guard to check if a value is an integer within specified bounds.
- * @param {unknown} value - The value to check
- * @param {number} lowerBound - The minimum allowed value (inclusive)
- * @returns True if the value is an integer >= lowerBound, false otherwise
- */ function isInteger(value, lowerBound) {
-    return typeof value === "number" && Number.isInteger(value) && value >= lowerBound;
-}
-/**
- * Converts a timestamp from the specified unit to microseconds.
- * @param {bigint} timestamp - The timestamp value as a bigint
- * @param {TimestampUnit} unit - The source timestamp unit
- * @returns The timestamp converted to microseconds
- * @throws Error if the timestamp unit is unknown
- */ function timestampToMicros(timestamp, unit) {
-    switch(unit){
-        case "ns":
-            return timestamp / 1000n;
-        case "us":
-            return timestamp;
-        case "ms":
-            return timestamp * 1000n;
-        default:
-            throw new Error(`Unknown timestamp unit: ${unit}`);
-    }
-}
-/**
- * Converts a timestamp from the specified unit to nanoseconds.
- * @param {bigint} timestamp - The timestamp value as a bigint
- * @param {TimestampUnit} unit - The source timestamp unit
- * @returns The timestamp converted to nanoseconds
- * @throws Error if the timestamp unit is unknown
- */ function timestampToNanos(timestamp, unit) {
-    switch(unit){
-        case "ns":
-            return timestamp;
-        case "us":
-            return timestamp * 1000n;
-        case "ms":
-            return timestamp * 1000_000n;
-        default:
-            throw new Error(`Unknown timestamp unit: ${unit}`);
-    }
-}
-/**
- * Analyzes the dimensions of a nested array structure.
- * @param {unknown} data - The array to analyze
- * @returns Array of dimension sizes at each nesting level
- * @throws Error if any dimension has zero length
- */ function getDimensions(data) {
-    const dimensions = [];
-    while(Array.isArray(data)){
-        dimensions.push(data.length);
-        data = data[0];
-    }
-    return dimensions;
-}
-/**
- * Validates an array structure. <br>
- * Validation fails if:
- * - <i>data</i> is not an array
- * - the array is irregular: the length of its sub-arrays are different
- * - the array is not homogenous: the array contains mixed types
- * @param {unknown[]} data - The array to validate
- * @param {number[]} dimensions - The shape of the array
- * @returns The primitive type of the array's elements
- * @throws Error if the validation fails
- */ function validateArray(data, dimensions) {
-    if (data === null || data === undefined) {
-        return null;
-    }
-    if (!Array.isArray(data)) {
-        throw new Error(`The value must be an array [value=${JSON.stringify(data)}, type=${typeof data}]`);
-    }
-    let expectedType = null;
-    function checkArray(array, depth = 0, path = "") {
-        const expectedLength = dimensions[depth];
-        if (array.length !== expectedLength) {
-            throw new Error(`Lengths of sub-arrays do not match [expected=${expectedLength}, actual=${array.length}, dimensions=[${dimensions}], path=${path}]`);
-        }
-        if (depth < dimensions.length - 1) {
-            // intermediate level, expecting arrays
-            for(let i = 0; i < array.length; i++){
-                if (!Array.isArray(array[i])) {
-                    throw new Error(`Mixed types found [expected=array, current=${typeof array[i]}, path=${path}[${i}]]`);
-                }
-                checkArray(array[i], depth + 1, `${path}[${i}]`);
-            }
-        } else {
-            // leaf level, expecting primitives
-            if (expectedType === null && array[0] !== undefined) {
-                expectedType = typeof array[0];
-            }
-            for(let i = 0; i < array.length; i++){
-                const currentType = typeof array[i];
-                if (currentType !== expectedType) {
-                    throw new Error(expectedType !== null ? `Mixed types found [expected=${expectedType}, current=${currentType}, path=${path}[${i}]]` : `Unsupported array type [type=${currentType}]`);
-                }
-            }
-        }
-    }
-    checkArray(data);
-    return expectedType;
-}
-/**
- * Fetches JSON data from a URL.
- * @template T - The expected type of the JSON response
- * @param {string} url - The URL to fetch from
- * @param {Agent} agent - HTTP agent to be used for the request
- * @param {number} timeout - Request timeout, query will be aborted if not finished in time
- * @returns Promise resolving to the parsed JSON data
- * @throws Error if the request fails or returns a non-OK status
- */ async function fetchJson(url, timeout, agent) {
-    const controller = new AbortController();
-    const { signal } = controller;
-    const timeoutId = setTimeout(()=>controller.abort(), timeout);
-    let response;
-    try {
-        response = await fetch(url, {
-            dispatcher: agent,
-            signal
-        });
-    } catch (error) {
-        throw new Error(`Failed to load ${url} [error=${error}]`);
-    } finally{
-        clearTimeout(timeoutId);
-    }
-    if (!response.ok) {
-        throw new Error(`Failed to load ${url} [statusCode=${response.status} (${response.statusText})]`);
-    }
-    return await response.json();
-}
-
-// @ts-check
-// HTTP status code for successful request with no content.
-const HTTP_NO_CONTENT = 204;
-// Default number of rows that trigger auto-flush for HTTP transport.
-const DEFAULT_HTTP_AUTO_FLUSH_ROWS = 75000;
-// Default minimum throughput for HTTP requests (100 KB/sec).
-const DEFAULT_REQUEST_MIN_THROUGHPUT = 102400;
-// Default request timeout in milliseconds (10 seconds).
-const DEFAULT_REQUEST_TIMEOUT = 10000;
-// Default retry timeout in milliseconds (10 seconds).
-const DEFAULT_RETRY_TIMEOUT = 10000;
-// HTTP status codes that should trigger request retries.
-// Includes server errors and gateway timeouts that may be transient.
-const RETRIABLE_STATUS_CODES = [
-    500,
-    503,
-    504,
-    507,
-    509,
-    523,
-    524,
-    529,
-    599
-];
-/**
- * Abstract base class for HTTP-based transport implementations. <br>
- * Provides common configuration and functionality for HTTP and HTTPS protocols.
- */ class HttpTransportBase {
-    /**
-   * Creates a new HttpTransportBase instance.
-   *
-   * @param {SenderOptions} options - Sender configuration options including connection and authentication details
-   * @throws Error if required protocol or host options are missing
-   */ constructor(options){
-        if (!options || !options.protocol) {
-            throw new Error("The 'protocol' option is mandatory");
-        }
-        if (!options.host) {
-            throw new Error("The 'host' option is mandatory");
-        }
-        this.log = typeof options.log === "function" ? options.log : log;
-        this.tlsVerify = isBoolean(options.tls_verify) ? options.tls_verify : true;
-        this.tlsCA = options.tls_ca ? node_fs.readFileSync(options.tls_ca) : undefined;
-        this.username = options.username;
-        this.password = options.password;
-        this.token = options.token;
-        if (!options.port) {
-            options.port = 9000;
-        }
-        this.host = options.host;
-        this.port = options.port;
-        this.requestMinThroughput = isInteger(options.request_min_throughput, 0) ? options.request_min_throughput : DEFAULT_REQUEST_MIN_THROUGHPUT;
-        this.requestTimeout = isInteger(options.request_timeout, 1) ? options.request_timeout : DEFAULT_REQUEST_TIMEOUT;
-        this.retryTimeout = isInteger(options.retry_timeout, 0) ? options.retry_timeout : DEFAULT_RETRY_TIMEOUT;
-        switch(options.protocol){
-            case HTTP:
-                this.secure = false;
-                break;
-            case HTTPS:
-                this.secure = true;
-                break;
-            default:
-                throw new Error("The 'protocol' has to be 'http' or 'https' for the HTTP transport");
-        }
-    }
-    /**
-   * HTTP transport does not require explicit connection establishment.
-   * @throws Error indicating connect is not required for HTTP transport
-   */ connect() {
-        throw new Error("'connect()' is not required for HTTP transport");
-    }
-    /**
-   * HTTP transport does not require explicit connection closure.
-   * @returns Promise that resolves immediately
-   */ async close() {}
-    /**
-   * Gets the default auto-flush row count for HTTP transport.
-   * @returns {number} Default number of rows that trigger auto-flush
-   */ getDefaultAutoFlushRows() {
-        return DEFAULT_HTTP_AUTO_FLUSH_ROWS;
-    }
-}
-
-const HTTP_PORT = 9000;
-const TCP_PORT = 9009;
-const HTTP = "http";
-const HTTPS = "https";
-const TCP = "tcp";
-const TCPS = "tcps";
-const ON = "on";
-const OFF = "off";
-const UNSAFE_OFF = "unsafe_off";
-const PROTOCOL_VERSION_AUTO = "auto";
-const PROTOCOL_VERSION_V1 = "1";
-const PROTOCOL_VERSION_V2 = "2";
-const LINE_PROTO_SUPPORT_VERSION = "line.proto.support.versions";
-/** @classdesc
- * <a href="Sender.html">Sender</a> configuration options. <br>
- * <br>
- * Properties of the object are initialized through a configuration string. <br>
- * The configuration string has the following format: <i>&ltprotocol&gt::&ltkey&gt=&ltvalue&gt;&ltkey&gt=&ltvalue&gt;...;</i> <br>
- * The keys are case-sensitive, the trailing semicolon is optional. <br>
- * The values are validated and an error is thrown if the format is invalid. <br>
- * <br>
- * Connection and protocol options
- * <ul>
- * <li> <b>protocol</b>: <i>enum, accepted values: http, https, tcp, tcps</i> - The protocol used to communicate with the server. <br>
- * When <i>https</i> or <i>tcps</i> used, the connection is secured with TLS encryption.
- * </li>
- * <li> <b>protocol_version</b>: <i>enum, accepted values: auto, 1, 2</i> - The protocol version used for data serialization. <br>
- * Version 1 uses text-based serialization for all data types. Version 2 uses binary encoding for doubles and arrays. <br>
- * When set to 'auto' (default for HTTP/HTTPS), the client automatically negotiates the highest supported version with the server. <br>
- * TCP/TCPS connections default to version 1.
- * </li>
- * <li> addr: <i>string</i> - Hostname and port, separated by colon. This key is mandatory, but the port part is optional. <br>
- * If no port is specified, a default will be used. <br>
- * When the protocol is HTTP/HTTPS, the port defaults to 9000. When the protocol is TCP/TCPS, the port defaults to 9009. <br>
- * <br>
- * Examples: <i>http::addr=localhost:9000</i>, <i>https::addr=localhost:9000</i>, <i>http::addr=localhost</i>, <i>tcp::addr=localhost:9009</i>
- * </li>
- * </ul>
- * <br>
- * Authentication options
- * <ul>
- * <li> username: <i>string</i> - Used for authentication. <br>
- * For HTTP, Basic Authentication requires the <i>password</i> option. <br>
- * For TCP with JWK token authentication, <i>token</i> option is required.
- * </li>
- * <li> password: <i>string</i> - Password for HTTP Basic authentication, should be accompanied by the <i>username</i> option.
- * </li>
- * <li> token: <i>string</i> - For HTTP with Bearer authentication, this is the bearer token. <br>
- * For TCP with JWK token authentication, this is the private key part of the JWK token,
- * and must be accompanied by the <i>username</i> option.
- * </li>
- * </ul>
- * <br>
- * TLS options
- * <ul>
- * <li> tls_verify: <i>enum, accepted values: on, unsafe_off</i> - When the HTTPS or TCPS protocols are selected, TLS encryption is used. <br>
- * By default, the Sender will verify the server's certificate, but this check can be disabled by setting this option to <i>unsafe_off</i>. <br>
- * This is useful in non-production environments where self-signed certificates might be used, but should be avoided in production if possible.
- * </li>
- * <li> tls_ca: <i>string</i> - Path to a file containing the root CA's certificate in PEM format. <br>
- * Can be useful when self-signed certificates are used, otherwise should not be set.
- * </li>
- * </ul>
- * <br>
- * Auto flush options
- * <ul>
- * <li> auto_flush: <i>enum, accepted values: on, off</i> - The Sender automatically flushes the buffer by default. This can be switched off
- * by setting this option to <i>off</i>. <br>
- * When disabled, the flush() method of the Sender has to be called explicitly to make sure data is sent to the server. <br>
- * Manual buffer flushing can be useful, especially when we want to control transaction boundaries. <br>
- * When the HTTP protocol is used, each flush results in a single HTTP request, which becomes a single transaction on the server side. <br>
- * The transaction either succeeds, and all rows sent in the request are inserted; or it fails, and none of the rows make it into the database.
- * </li>
- * <li> auto_flush_rows: <i>integer</i> - The number of rows that will trigger a flush. When set to 0, row-based flushing is disabled. <br>
- * The Sender will default this parameter to 75000 rows when HTTP protocol is used, and to 600 in case of TCP protocol.
- * </li>
- * <li> auto_flush_interval: <i>integer</i> - The number of milliseconds that will trigger a flush, default value is 1000.
- * When set to 0, interval-based flushing is disabled. <br>
- * Note that the setting is checked only when a new row is added to the buffer. There is no timer registered to flush the buffer automatically.
- * </li>
- * </ul>
- * <br>
- * Buffer sizing options
- * <ul>
- * <li> init_buf_size: <i>integer</i> - Initial buffer size, defaults to 64 KiB in the Sender.
- * </li>
- * <li> max_buf_size: <i>integer</i> - Maximum buffer size, defaults to 100 MiB in the Sender. <br>
- * If the buffer would need to be extended beyond the maximum size, an error is thrown.
- * </li>
- * </ul>
- * <br>
- * HTTP request specific options
- * <ul>
- * <li> request_timeout: <i>integer</i> - The time in milliseconds to wait for a response from the server, set to 10 seconds by default. <br>
- * This is in addition to the calculation derived from the <i>request_min_throughput</i> parameter.
- * </li>
- * <li> request_min_throughput: <i>integer</i> - Minimum expected throughput in bytes per second for HTTP requests, set to 100 KiB/s seconds by default. <br>
- * If the throughput is lower than this value, the connection will time out. This is used to calculate an additional
- * timeout on top of <i>request_timeout</i>. This is useful for large requests. You can set this value to 0 to disable this logic.
- * </li>
- * <li> retry_timeout: <i>integer</i> - The time in milliseconds to continue retrying after a failed HTTP request, set to 10 seconds by default. <br>
- * The interval between retries is an exponential backoff starting at 10ms and doubling after each failed attempt up to a maximum of 1 second.
- * </li>
- * </ul>
- * <br>
- * Other options
- * <ul>
- * <li> stdlib_http: <i>enum, accepted values: on, off</i> - With HTTP protocol the Undici library is used by default. By setting this option
- * to <i>on</i> the client switches to node's core http and https modules.
- * </li>
- * <li> max_name_len: <i>integer</i> - The maximum length of a table or column name, the Sender defaults this parameter to 127. <br>
- * Recommended to use the same setting as the server, which also uses 127 by default.
- * </li>
- * </ul>
- */ class SenderOptions {
-    /**
-   * Creates a Sender options object by parsing the provided configuration string.
-   *
-   * @param {string} configurationString - Configuration string. <br>
-   * @param {object} extraOptions - Optional extra configuration. <br>
-   * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-   * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-   * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-   * Depends on which transport implementation and protocol used, one of the followings expected: <i>undici.Agent</i>, <i>http.Agent</i> or <i>https.Agent</i>.
-   */ constructor(configurationString, extraOptions){
-        parseConfigurationString(this, configurationString);
-        if (extraOptions) {
-            if (extraOptions.log && typeof extraOptions.log !== "function") {
-                throw new Error("Invalid logging function");
-            }
-            this.log = extraOptions.log;
-            if (extraOptions.agent && !(extraOptions.agent instanceof undici.Agent) && !(extraOptions.agent instanceof http__default.default.Agent) && // @ts-expect-error - Not clear what the problem is, the two lines above have no issues
-            !(extraOptions.agent instanceof https__default.default.Agent)) {
-                throw new Error("Invalid HTTP agent");
-            }
-            this.agent = extraOptions.agent;
-        }
-    }
-    /**
-   * Resolves the protocol version, if it is set to 'auto'. <br>
-   * If TCP transport is used, the protocol version will default to 1.
-   * In case of HTTP transport the <i>/settings</i> endpoint of the database is used to find the protocol versions
-   * supported by the server, and the highest will be selected.
-   * When calling the <i>/settings</i> endpoint the timeout and TLs options are used from the <i>options</i> object.
-   * @param {SenderOptions} options SenderOptions instance needs resolving protocol version
-   */ static async resolveAuto(options) {
-        parseProtocolVersion(options);
-        if (options.protocol_version !== PROTOCOL_VERSION_AUTO) {
-            return options;
-        }
-        const url = `${options.protocol}://${options.host}:${options.port}/settings`;
-        const settings = await fetchJson(url, isInteger(options.request_timeout, 1) ? options.request_timeout : DEFAULT_REQUEST_TIMEOUT, new undici.Agent({
-            connect: {
-                ca: options.tls_ca ? node_fs.readFileSync(options.tls_ca) : undefined,
-                rejectUnauthorized: isBoolean(options.tls_verify) ? options.tls_verify : true
-            }
-        }));
-        const supportedVersions = (settings.config[LINE_PROTO_SUPPORT_VERSION] ?? []).map((version)=>String(version));
-        if (supportedVersions.length === 0) {
-            options.protocol_version = PROTOCOL_VERSION_V1;
-        } else if (supportedVersions.includes(PROTOCOL_VERSION_V2)) {
-            options.protocol_version = PROTOCOL_VERSION_V2;
-        } else if (supportedVersions.includes(PROTOCOL_VERSION_V1)) {
-            options.protocol_version = PROTOCOL_VERSION_V1;
-        } else {
-            throw new Error("Unsupported protocol versions received from server: " + supportedVersions);
-        }
-        return options;
-    }
-    static resolveDeprecated(options, log) {
-        if (!options) {
-            return;
-        }
-        // deal with deprecated options
-        if (options.copy_buffer !== undefined) {
-            log("warn", `Option 'copy_buffer' is not supported anymore, please, remove it`);
-            options.copy_buffer = undefined;
-        }
-        if (options.copyBuffer !== undefined) {
-            log("warn", `Option 'copyBuffer' is not supported anymore, please, remove it`);
-            options.copyBuffer = undefined;
-        }
-        if (options.bufferSize !== undefined) {
-            log("warn", `Option 'bufferSize' is not supported anymore, please, replace it with 'init_buf_size'`);
-            options.init_buf_size = options.bufferSize;
-            options.bufferSize = undefined;
-        }
-    }
-    /**
-   * Creates a Sender options object by parsing the provided configuration string.
-   *
-   * @param {string} configurationString - Configuration string. <br>
-   * @param {object} extraOptions - Optional extra configuration. <br>
-   * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-   * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-   * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-   * Depends on which transport implementation and protocol used, one of the followings expected: <i>undici.Agent</i>, <i>http.Agent</i> or <i>https.Agent</i>.
-   *
-   * @return {SenderOptions} A Sender configuration object initialized from the provided configuration string.
-   */ static async fromConfig(configurationString, extraOptions) {
-        const options = new SenderOptions(configurationString, extraOptions);
-        await SenderOptions.resolveAuto(options);
-        return options;
-    }
-    /**
-   * Creates a Sender options object by parsing the configuration string set in the <b>QDB_CLIENT_CONF</b> environment variable.
-   *
-   * @param {object} extraOptions - Optional extra configuration. <br>
-   * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-   * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-   * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-   * Depends on which transport implementation and protocol used, one of the followings expected: <i>undici.Agent</i>, <i>http.Agent</i> or <i>https.Agent</i>.
-   *
-   * @return {SenderOptions} A Sender configuration object initialized from the <b>QDB_CLIENT_CONF</b> environment variable.
-   */ static async fromEnv(extraOptions) {
-        return await SenderOptions.fromConfig(process.env.QDB_CLIENT_CONF, extraOptions);
-    }
-}
-function parseConfigurationString(options, configString) {
-    if (!configString) {
-        throw new Error("Configuration string is missing or empty");
-    }
-    const position = parseProtocol(options, configString);
-    parseSettings(options, configString, position);
-    parseProtocolVersion(options);
-    parseAddress(options);
-    parseBufferSizes(options);
-    parseAutoFlushOptions(options);
-    parseTlsOptions(options);
-    parseRequestTimeoutOptions(options);
-    parseMaxNameLength(options);
-    parseStdlibTransport(options);
-}
-function parseSettings(options, configString, position) {
-    let index = configString.indexOf(";", position);
-    while(index > -1){
-        if (index + 1 < configString.length && configString.charAt(index + 1) === ";") {
-            index = configString.indexOf(";", index + 2);
-            continue;
-        }
-        parseSetting(options, configString, position, index);
-        position = index + 1;
-        index = configString.indexOf(";", position);
-    }
-    if (position < configString.length) {
-        parseSetting(options, configString, position, configString.length);
-    }
-}
-function parseSetting(options, configString, position, index) {
-    const setting = configString.slice(position, index).replaceAll(";;", ";");
-    const equalsIndex = setting.indexOf("=");
-    if (equalsIndex < 0) {
-        throw new Error(`Missing '=' sign in '${setting}'`);
-    }
-    const key = setting.slice(0, equalsIndex);
-    const value = setting.slice(equalsIndex + 1);
-    validateConfigKey(key);
-    validateConfigValue(key, value);
-    options[key] = value;
-}
-const ValidConfigKeys = [
-    "protocol_version",
-    "addr",
-    "username",
-    "password",
-    "token",
-    "token_x",
-    "token_y",
-    "auto_flush",
-    "auto_flush_rows",
-    "auto_flush_interval",
-    "request_min_throughput",
-    "request_timeout",
-    "retry_timeout",
-    "init_buf_size",
-    "max_buf_size",
-    "max_name_len",
-    "stdlib_http",
-    "tls_verify",
-    "tls_ca",
-    "tls_roots",
-    "tls_roots_password"
-];
-function validateConfigKey(key) {
-    if (!ValidConfigKeys.includes(key)) {
-        throw new Error(`Unknown configuration key: '${key}'`);
-    }
-}
-function validateConfigValue(key, value) {
-    if (!value) {
-        throw new Error(`Invalid configuration, value is not set for '${key}'`);
-    }
-    for(let i = 0; i < value.length; i++){
-        const unicode = value.codePointAt(i);
-        if (unicode < 0x20 || unicode > 0x7e && unicode < 0xa0) {
-            throw new Error(`Invalid configuration, control characters are not allowed: '${value}'`);
-        }
-    }
-}
-function parseProtocol(options, configString) {
-    const index = configString.indexOf("::");
-    if (index < 0) {
-        throw new Error("Missing protocol, configuration string format: 'protocol::key1=value1;key2=value2;key3=value3;'");
-    }
-    options.protocol = configString.slice(0, index);
-    switch(options.protocol){
-        case HTTP:
-        case HTTPS:
-        case TCP:
-        case TCPS:
-            break;
-        default:
-            throw new Error(`Invalid protocol: '${options.protocol}', accepted protocols: 'http', 'https', 'tcp', 'tcps'`);
-    }
-    return index + 2;
-}
-function parseProtocolVersion(options) {
-    const protocol_version = options.protocol_version ?? PROTOCOL_VERSION_AUTO;
-    switch(protocol_version){
-        case PROTOCOL_VERSION_AUTO:
-            switch(options.protocol){
-                case HTTP:
-                case HTTPS:
-                    options.protocol_version = PROTOCOL_VERSION_AUTO;
-                    break;
-                default:
-                    options.protocol_version = PROTOCOL_VERSION_V1;
-            }
-            break;
-        case PROTOCOL_VERSION_V1:
-        case PROTOCOL_VERSION_V2:
-            break;
-        default:
-            throw new Error(`Invalid protocol version: '${protocol_version}', accepted values: 'auto', '1', '2'`);
-    }
-    return;
-}
-function parseAddress(options) {
-    if (!options.addr) {
-        throw new Error("Invalid configuration, 'addr' is required");
-    }
-    const index = options.addr.indexOf(":");
-    if (index < 0) {
-        options.host = options.addr;
-        switch(options.protocol){
-            case HTTP:
-            case HTTPS:
-                options.port = HTTP_PORT;
-                return;
-            case TCP:
-            case TCPS:
-                options.port = TCP_PORT;
-                return;
-            default:
-                throw new Error(`Invalid protocol: '${options.protocol}', accepted protocols: 'http', 'https', 'tcp', 'tcps'`);
-        }
-    }
-    options.host = options.addr.slice(0, index);
-    if (!options.host) {
-        throw new Error(`Host name is required`);
-    }
-    const portStr = options.addr.slice(index + 1);
-    if (!portStr) {
-        throw new Error(`Port is required`);
-    }
-    options.port = Number(portStr);
-    if (isNaN(options.port)) {
-        throw new Error(`Invalid port: '${portStr}'`);
-    }
-    if (!Number.isInteger(options.port) || options.port < 1) {
-        throw new Error(`Invalid port: ${options.port}`);
-    }
-}
-function parseBufferSizes(options) {
-    parseInteger(options, "init_buf_size", "initial buffer size", 1);
-    parseInteger(options, "max_buf_size", "max buffer size", 1);
-}
-function parseAutoFlushOptions(options) {
-    parseBoolean(options, "auto_flush", "auto flush");
-    parseInteger(options, "auto_flush_rows", "auto flush rows", 0);
-    parseInteger(options, "auto_flush_interval", "auto flush interval", 0);
-}
-function parseTlsOptions(options) {
-    parseBoolean(options, "tls_verify", "TLS verify", UNSAFE_OFF);
-    if (options.tls_roots || options.tls_roots_password) {
-        throw new Error("'tls_roots' and 'tls_roots_password' options are not supported, please, " + "use the 'tls_ca' option or the NODE_EXTRA_CA_CERTS environment variable instead");
-    }
-}
-function parseRequestTimeoutOptions(options) {
-    parseInteger(options, "request_min_throughput", "request min throughput", 1);
-    parseInteger(options, "request_timeout", "request timeout", 1);
-    parseInteger(options, "retry_timeout", "retry timeout", 0);
-}
-function parseMaxNameLength(options) {
-    parseInteger(options, "max_name_len", "max name length", 1);
-}
-function parseStdlibTransport(options) {
-    parseBoolean(options, "stdlib_http", "stdlib http");
-}
-function parseBoolean(options, property, description, offValue = OFF) {
-    if (options[property]) {
-        const property_str = options[property];
-        switch(property_str){
-            case ON:
-                options[property] = true;
-                break;
-            case offValue:
-                options[property] = false;
-                break;
-            default:
-                throw new Error(`Invalid ${description} option: '${property_str}'`);
-        }
-    }
-}
-function parseInteger(options, property, description, lowerBound) {
-    if (options[property]) {
-        const property_str = options[property];
-        options[property] = Number(property_str);
-        if (isNaN(options[property])) {
-            throw new Error(`Invalid ${description} option, not a number: '${property_str}'`);
-        }
-        if (!Number.isInteger(options[property]) || options[property] < lowerBound) {
-            throw new Error(`Invalid ${description} option: ${options[property]}`);
-        }
-    }
-}
-
-// @ts-check
-/**
- * Default HTTP options for the Undici agent.
- * Configures keep-alive connections with 60-second timeout and single request pipelining.
- */ const DEFAULT_HTTP_OPTIONS = {
-    connect: {
-        keepAlive: true
-    },
-    pipelining: 1,
-    keepAliveTimeout: 60000
-};
-/**
- * HTTP transport implementation using the Undici library. <br>
- * Provides high-performance HTTP requests with connection pooling and retry logic. <br>
- * Supports both HTTP and HTTPS protocols with configurable authentication.
- */ class UndiciTransport extends HttpTransportBase {
-    /**
-   * Creates a new UndiciTransport instance.
-   *
-   * @param options - Sender configuration object containing connection and retry settings
-   * @throws Error if the protocol is not 'http' or 'https'
-   */ constructor(options){
-        super(options);
-        switch(options.protocol){
-            case HTTP:
-                this.agent = options.agent instanceof undici.Agent ? options.agent : UndiciTransport.getDefaultHttpAgent();
-                break;
-            case HTTPS:
-                if (options.agent instanceof undici.Agent) {
-                    this.agent = options.agent;
-                } else {
-                    // Create a new agent with instance-specific TLS options
-                    this.agent = new undici.Agent({
-                        ...DEFAULT_HTTP_OPTIONS,
-                        connect: {
-                            ...DEFAULT_HTTP_OPTIONS.connect,
-                            requestCert: this.tlsVerify,
-                            rejectUnauthorized: this.tlsVerify,
-                            ca: this.tlsCA
-                        }
-                    });
-                }
-                break;
-            default:
-                throw new Error("The 'protocol' has to be 'http' or 'https' for the Undici HTTP transport");
-        }
-        this.dispatcher = new undici.RetryAgent(this.agent, {
-            maxRetries: Infinity,
-            minTimeout: 10,
-            maxTimeout: 1000,
-            timeoutFactor: 2,
-            retryAfter: true,
-            methods: [
-                "GET",
-                "POST",
-                "PUT",
-                "DELETE",
-                "PATCH",
-                "OPTIONS",
-                "HEAD"
-            ],
-            statusCodes: RETRIABLE_STATUS_CODES,
-            errorCodes: [
-                "ECONNRESET",
-                "EAI_AGAIN",
-                "ECONNREFUSED",
-                "ETIMEDOUT",
-                "EPIPE",
-                "UND_ERR_CONNECT_TIMEOUT",
-                "UND_ERR_HEADERS_TIMEOUT",
-                "UND_ERR_BODY_TIMEOUT"
-            ]
-        });
-    }
-    /**
-   * Sends data to QuestDB using HTTP POST.
-   *
-   * @param {Buffer} data - Buffer containing the data to send
-   * @returns Promise resolving to true if data was sent successfully
-   * @throws Error if request fails after all retries or times out
-   */ async send(data) {
-        const headers = {};
-        if (this.token) {
-            headers["Authorization"] = `Bearer ${this.token}`;
-        } else if (this.username && this.password) {
-            headers["Authorization"] = `Basic ${node_buffer.Buffer.from(`${this.username}:${this.password}`).toString("base64")}`;
-        }
-        const controller = new AbortController();
-        const { signal } = controller;
-        setTimeout(()=>controller.abort(), this.retryTimeout);
-        let responseData;
-        try {
-            const timeoutMillis = data.length / this.requestMinThroughput * 1000 + this.requestTimeout;
-            responseData = await this.dispatcher.request({
-                origin: `${this.secure ? "https" : "http"}://${this.host}:${this.port}`,
-                path: "/write?precision=n",
-                method: "POST",
-                headers,
-                body: data,
-                headersTimeout: this.requestTimeout,
-                bodyTimeout: timeoutMillis,
-                signal
-            });
-        } catch (err) {
-            if (err.name === "AbortError") {
-                throw new Error("HTTP request timeout, no response from server in time");
-            } else {
-                throw err;
-            }
-        }
-        const { statusCode } = responseData;
-        const body = await responseData.body.arrayBuffer();
-        if (statusCode === HTTP_NO_CONTENT) {
-            if (body.byteLength > 0) {
-                const message = node_buffer.Buffer.from(body).toString();
-                const logMessage = message.length < 256 ? message : `${message.substring(0, 256)}... (truncated, full length=${message.length})`;
-                this.log("warn", `Unexpected message from server: ${logMessage}`);
-            }
-            return true;
-        } else {
-            throw new Error(`HTTP request failed, statusCode=${statusCode}, error=${node_buffer.Buffer.from(body).toString()}`);
-        }
-    }
-    /**
-   * @ignore
-   * Gets or creates the default HTTP agent with standard configuration.
-   * Uses a singleton pattern to reuse the same agent across instances.
-   * @returns The default Undici agent instance
-   */ static getDefaultHttpAgent() {
-        if (!UndiciTransport.DEFAULT_HTTP_AGENT) {
-            UndiciTransport.DEFAULT_HTTP_AGENT = new undici.Agent(DEFAULT_HTTP_OPTIONS);
-        }
-        return UndiciTransport.DEFAULT_HTTP_AGENT;
-    }
-}
-
-// @ts-check
-// Default number of rows that trigger auto-flush for TCP transport.
-const DEFAULT_TCP_AUTO_FLUSH_ROWS = 600;
-// Arbitrary public key, used to construct valid JWK tokens.
-// These are not used for actual authentication, only required for crypto API compatibility.
-const PUBLIC_KEY = {
-    x: "aultdA0PjhD_cWViqKKyL5chm6H1n-BiZBo_48T-uqc",
-    y: "__ptaol41JWSpTTL525yVEfzmY8A6Vi_QrW1FjKcHMg"
-};
-/**
- * TCP transport implementation. <br>
- * Supports both plain TCP or secure TLS-encrypted connections with configurable JWK token authentication.
- */ class TcpTransport {
-    /**
-   * Creates a new TcpTransport instance.
-   *
-   * @param {SenderOptions} options - Sender configuration object containing connection and authentication details
-   * @throws Error if required options are missing or protocol is not 'tcp' or 'tcps'
-   */ constructor(options){
-        if (!options || !options.protocol) {
-            throw new Error("The 'protocol' option is mandatory");
-        }
-        if (!options.host) {
-            throw new Error("The 'host' option is mandatory");
-        }
-        this.log = typeof options.log === "function" ? options.log : log;
-        this.tlsVerify = isBoolean(options.tls_verify) ? options.tls_verify : true;
-        this.tlsCA = options.tls_ca ? node_fs.readFileSync(options.tls_ca) : undefined;
-        this.host = options.host;
-        this.port = options.port;
-        switch(options.protocol){
-            case TCP:
-                this.secure = false;
-                break;
-            case TCPS:
-                this.secure = true;
-                break;
-            default:
-                throw new Error("The 'protocol' has to be 'tcp' or 'tcps' for the TCP transport");
-        }
-        if (!options.auth && !options.jwk) {
-            constructAuth(options);
-        }
-        this.jwk = constructJwk(options);
-        if (!options.port) {
-            options.port = 9009;
-        }
-    }
-    /**
-   * Creates a TCP connection to the database.
-   * @returns Promise resolving to true if the connection is established successfully
-   * @throws Error if connection fails or authentication is rejected
-   */ connect() {
-        const connOptions = {
-            host: this.host,
-            port: this.port,
-            ca: this.tlsCA
-        };
-        return new Promise((resolve, reject)=>{
-            if (this.socket) {
-                throw new Error("Sender connected already");
-            }
-            let authenticated = false;
-            let data;
-            this.socket = !this.secure ? net__default.default.connect(connOptions) : tls__default.default.connect(connOptions, ()=>{
-                if (authenticated) {
-                    resolve(true);
-                }
-            });
-            this.socket.setKeepAlive(true);
-            this.socket.on("data", async (raw)=>{
-                data = !data ? raw : node_buffer.Buffer.concat([
-                    data,
-                    raw
-                ]);
-                if (!authenticated) {
-                    authenticated = await this.authenticate(data);
-                    if (authenticated) {
-                        resolve(true);
-                    }
-                } else {
-                    this.log("warn", `Received unexpected data: ${data}`);
-                }
-            }).on("ready", async ()=>{
-                this.log("info", `Successfully connected to ${connOptions.host}:${connOptions.port}`);
-                if (this.jwk) {
-                    this.log("info", `Authenticating with ${connOptions.host}:${connOptions.port}`);
-                    this.socket.write(`${this.jwk.kid}\n`, (err)=>err ? reject(err) : ()=>{});
-                } else {
-                    authenticated = true;
-                    if (!this.secure || !this.tlsVerify) {
-                        resolve(true);
-                    }
-                }
-            }).on("error", (err)=>{
-                this.log("error", err);
-                if (this.tlsVerify || !err.code || err.code !== "SELF_SIGNED_CERT_IN_CHAIN") {
-                    reject(err);
-                }
-            });
-        });
-    }
-    /**
-   * Sends data over the established TCP connection.
-   * @param {Buffer} data - Buffer containing the data to send
-   * @returns Promise resolving to true if data was sent successfully
-   * @throws Error if the data could not be written to the socket
-   */ send(data) {
-        if (!this.socket || this.socket.destroyed) {
-            throw new Error("TCP transport is not connected");
-        }
-        return new Promise((resolve, reject)=>{
-            this.socket.write(data, (err)=>{
-                if (err) {
-                    reject(err);
-                } else {
-                    resolve(true);
-                }
-            });
-        });
-    }
-    /**
-   * Closes the TCP connection to the database.
-   */ async close() {
-        if (this.socket) {
-            const address = this.socket.remoteAddress;
-            const port = this.socket.remotePort;
-            this.socket.destroy();
-            this.socket = null;
-            this.log("info", `Connection to ${address}:${port} is closed`);
-        }
-    }
-    /**
-   * Gets the default auto-flush row count for TCP transport.
-   * @returns Default number of rows that trigger auto-flush
-   */ getDefaultAutoFlushRows() {
-        return DEFAULT_TCP_AUTO_FLUSH_ROWS;
-    }
-    /**
-   * @ignore
-   * Handles the JWK token authentication challenge-response flow.
-   * @param {Buffer} challenge - Challenge buffer received from the server
-   * @returns Promise resolving to true if authentication is successful
-   */ async authenticate(challenge) {
-        // Check for trailing \n which ends the challenge
-        if (challenge.subarray(-1).readInt8() === 10) {
-            const keyObject = crypto__default.default.createPrivateKey({
-                key: this.jwk,
-                format: "jwk"
-            });
-            const signature = crypto__default.default.sign("RSA-SHA256", challenge.subarray(0, challenge.length - 1), keyObject);
-            return new Promise((resolve, reject)=>{
-                this.socket.write(`${node_buffer.Buffer.from(signature).toString("base64")}\n`, (err)=>{
-                    if (err) {
-                        reject(err);
-                    } else {
-                        resolve(true);
-                    }
-                });
-            });
-        }
-        return false;
-    }
-}
-/**
- * @ignore
- * Constructs authentication configuration from username/token options.
- * @param {SenderOptions} options - Sender options that may contain authentication details
- * @throws Error if username or token is missing when authentication is intended
- */ function constructAuth(options) {
-    if (!options.username && !options.token && !options.password) {
-        // no intention to authenticate
-        return;
-    }
-    if (!options.username || !options.token) {
-        throw new Error("TCP transport requires a username and a private key for authentication, " + "please, specify the 'username' and 'token' config options");
-    }
-    options.auth = {
-        keyId: options.username,
-        token: options.token
-    };
-}
-/**
- * @ignore
- * Constructs a JWK (JSON Web Key) object for cryptographic authentication.
- * @param {SenderOptions} options - Sender options containing authentication configuration
- * @returns JWK object with key ID, private key, and public key coordinates
- * @throws Error if required authentication properties are missing or invalid
- */ function constructJwk(options) {
-    if (options.auth) {
-        if (!options.auth.keyId) {
-            throw new Error("Missing username, please, specify the 'keyId' property of the 'auth' config option. " + "For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})");
-        }
-        if (typeof options.auth.keyId !== "string") {
-            throw new Error("Please, specify the 'keyId' property of the 'auth' config option as a string. " + "For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})");
-        }
-        if (!options.auth.token) {
-            throw new Error("Missing private key, please, specify the 'token' property of the 'auth' config option. " + "For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})");
-        }
-        if (typeof options.auth.token !== "string") {
-            throw new Error("Please, specify the 'token' property of the 'auth' config option as a string. " + "For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})");
-        }
-        return {
-            kid: options.auth.keyId,
-            d: options.auth.token,
-            ...PUBLIC_KEY,
-            kty: "EC",
-            crv: "P-256"
-        };
-    } else {
-        return options.jwk;
-    }
-}
-
-// @ts-check
-/**
- * Default configuration for HTTP agents.
- * - Persistent connections with 1 minute idle timeout
- * - Maximum of 256 open connections (matching server default)
- */ const DEFAULT_HTTP_AGENT_CONFIG = {
-    maxSockets: 256,
-    keepAlive: true,
-    timeout: 60000
-};
-/**
- * HTTP transport implementation using Node.js built-in http/https modules. <br>
- * Supports both HTTP and HTTPS protocols with configurable authentication.
- */ class HttpTransport extends HttpTransportBase {
-    /**
-   * Creates a new HttpTransport instance using Node.js HTTP modules.
-   *
-   * @param {SenderOptions} options - Sender configuration object containing connection details
-   * @throws Error if the protocol is not 'http' or 'https'
-   */ constructor(options){
-        super(options);
-        switch(options.protocol){
-            case HTTP:
-                this.agent = options.agent instanceof http__default.default.Agent ? options.agent : HttpTransport.getDefaultHttpAgent();
-                break;
-            case HTTPS:
-                this.agent = options.agent instanceof https__default.default.Agent ? options.agent : HttpTransport.getDefaultHttpsAgent();
-                break;
-            default:
-                throw new Error("The 'protocol' has to be 'http' or 'https' for the HTTP transport");
-        }
-    }
-    /**
-   * Sends data to QuestDB using HTTP POST.
-   *
-   * @param {Buffer} data - Buffer containing the data to send
-   * @param {number} retryBegin - Internal parameter for tracking retry start time
-   * @param {number} retryInterval - Internal parameter for tracking retry intervals
-   * @returns Promise resolving to true if data was sent successfully
-   * @throws Error if request fails after all retries or times out
-   */ send(data, retryBegin = -1, retryInterval = -1) {
-        const request = this.secure ? https__default.default.request : http__default.default.request;
-        const timeoutMillis = data.length / this.requestMinThroughput * 1000 + this.requestTimeout;
-        const options = this.createRequestOptions(timeoutMillis);
-        return new Promise((resolve, reject)=>{
-            let statusCode = -1;
-            const req = request(options, (response)=>{
-                statusCode = response.statusCode;
-                const body = [];
-                response.on("data", (chunk)=>{
-                    body.push(chunk);
-                }).on("error", (err)=>{
-                    this.log("error", `resp err=${err}`);
-                });
-                if (statusCode === HTTP_NO_CONTENT) {
-                    response.on("end", ()=>{
-                        if (body.length > 0) {
-                            const message = node_buffer.Buffer.concat(body).toString();
-                            const logMessage = message.length < 256 ? message : `${message.substring(0, 256)}... (truncated, full length=${message.length})`;
-                            this.log("warn", `Unexpected message from server: ${logMessage}`);
-                        }
-                        resolve(true);
-                    });
-                } else {
-                    req.destroy(new Error(`HTTP request failed, statusCode=${statusCode}, error=${node_buffer.Buffer.concat(body)}`));
-                }
-            });
-            if (this.token) {
-                req.setHeader("Authorization", `Bearer ${this.token}`);
-            } else if (this.username && this.password) {
-                req.setHeader("Authorization", `Basic ${node_buffer.Buffer.from(`${this.username}:${this.password}`).toString("base64")}`);
-            }
-            req.on("timeout", ()=>{
-                // set a retryable error code
-                statusCode = 524;
-                req.destroy(new Error("HTTP request timeout, no response from server in time"));
-            });
-            req.on("error", (err)=>{
-                // if the error is thrown while the request is sent, statusCode is -1 => no retry
-                // request timeout comes through with statusCode 524 => retry
-                // if the error is thrown while the response is processed, the statusCode is taken from the response => retry depends on statusCode
-                if (isRetryable(statusCode) && this.retryTimeout > 0) {
-                    if (retryBegin < 0) {
-                        retryBegin = Date.now();
-                        retryInterval = 10;
-                    } else {
-                        const elapsed = Date.now() - retryBegin;
-                        if (elapsed > this.retryTimeout) {
-                            reject(err);
-                            return;
-                        }
-                    }
-                    const jitter = Math.floor(Math.random() * 10) - 5;
-                    setTimeout(()=>{
-                        retryInterval = Math.min(retryInterval * 2, 1000);
-                        this.send(data, retryBegin, retryInterval).then(()=>resolve(true)).catch((e)=>reject(e));
-                    }, retryInterval + jitter);
-                } else {
-                    reject(err);
-                }
-            });
-            req.write(data, (err)=>err ? reject(err) : ()=>{});
-            req.end();
-        });
-    }
-    /**
-   * @ignore
-   * Creates HTTP request options based on configuration.
-   *
-   * @param {number} timeoutMillis - Request timeout in milliseconds
-   * @returns HTTP or HTTPS request options object
-   */ createRequestOptions(timeoutMillis) {
-        return {
-            hostname: this.host,
-            port: this.port,
-            agent: this.agent,
-            path: "/write?precision=n",
-            method: "POST",
-            timeout: timeoutMillis,
-            rejectUnauthorized: this.secure && this.tlsVerify,
-            ca: this.secure ? this.tlsCA : undefined
-        };
-    }
-    /**
-   * @ignore
-   * Gets or creates the default HTTP agent with standard configuration.
-   * Uses a singleton pattern to reuse the same agent across instances.
-   * @returns The default HTTP agent instance
-   */ static getDefaultHttpAgent() {
-        if (!HttpTransport.DEFAULT_HTTP_AGENT) {
-            HttpTransport.DEFAULT_HTTP_AGENT = new http__default.default.Agent(DEFAULT_HTTP_AGENT_CONFIG);
-        }
-        return HttpTransport.DEFAULT_HTTP_AGENT;
-    }
-    /**
-   * @ignore
-   * Gets or creates the default HTTPS agent with standard configuration.
-   * Uses a singleton pattern to reuse the same agent across instances.
-   * @returns The default HTTPS agent instance
-   */ static getDefaultHttpsAgent() {
-        if (!HttpTransport.DEFAULT_HTTPS_AGENT) {
-            HttpTransport.DEFAULT_HTTPS_AGENT = new https__default.default.Agent(DEFAULT_HTTP_AGENT_CONFIG);
-        }
-        return HttpTransport.DEFAULT_HTTPS_AGENT;
-    }
-}
-/**
- * @ignore
- * Determines if an HTTP status code should trigger a retry.
- * @param {number} statusCode - HTTP status code to check
- * @returns True if the status code indicates a retryable error
- */ function isRetryable(statusCode) {
-    return RETRIABLE_STATUS_CODES.includes(statusCode);
-}
-
-// @ts-check
-/**
- * Factory function to create appropriate transport instance based on configuration.
- * @param {SenderOptions} options - Sender configuration options including protocol and connection details
- * @returns Transport instance appropriate for the specified protocol
- * @throws Error if protocol or host options are missing or invalid
- */ function createTransport(options) {
-    if (!options || !options.protocol) {
-        throw new Error("The 'protocol' option is mandatory");
-    }
-    if (!options.host) {
-        throw new Error("The 'host' option is mandatory");
-    }
-    switch(options.protocol){
-        case HTTP:
-        case HTTPS:
-            return options.stdlib_http ? new HttpTransport(options) : new UndiciTransport(options);
-        case TCP:
-        case TCPS:
-            return new TcpTransport(options);
-        default:
-            throw new Error(`Invalid protocol: '${options.protocol}'`);
-    }
-}
-
-/**
- * Validates a table name.
- *
- * @param {string} name - The table name to validate.
- * @param {number} maxNameLength - The maximum length of table names.
- * @throws Error if table name is invalid.
- */ function validateTableName(name, maxNameLength) {
-    const len = name.length;
-    if (len > maxNameLength) {
-        throw new Error(`Table name is too long, max length is ${maxNameLength}`);
-    }
-    if (len === 0) {
-        throw new Error("Empty string is not allowed as table name");
-    }
-    for(let i = 0; i < len; i++){
-        const ch = name[i];
-        switch(ch){
-            case ".":
-                if (i === 0 || i === len - 1 || name[i - 1] === ".") // single dot is allowed in the middle only
-                // starting with a dot hides directory in Linux
-                // ending with a dot can be trimmed by some Windows versions / file systems
-                // double or triple dot looks suspicious
-                // single dot allowed as compatibility,
-                // when someone uploads 'file_name.csv' the file name used as the table name
-                throw new Error("Table name cannot start or end with a dot, and only a single dot allowed");
-                break;
-            case "?":
-            case ",":
-            case "'":
-            case '"':
-            case "\\":
-            case "/":
-            case ":":
-            case ")":
-            case "(":
-            case "+":
-            case "*":
-            case "%":
-            case "~":
-            case "\u0000":
-            case "\u0001":
-            case "\u0002":
-            case "\u0003":
-            case "\u0004":
-            case "\u0005":
-            case "\u0006":
-            case "\u0007":
-            case "\u0008":
-            case "\u0009":
-            case "\u000B":
-            case "\u000c":
-            case "\r":
-            case "\n":
-            case "\u000e":
-            case "\u000f":
-            case "\u007f":
-            case "\ufeff":
-                throw new Error(`Invalid character in table name: ${ch}`);
-        }
-    }
-}
-/**
- * Validates a column name.
- *
- * @param {string} name - The column name to validate.
- * @param {number} maxNameLength - The maximum length of column names.
- * @throws Error if column name is invalid.
- */ function validateColumnName(name, maxNameLength) {
-    const len = name.length;
-    if (len > maxNameLength) {
-        throw new Error(`Column name is too long, max length is ${maxNameLength}`);
-    }
-    if (len === 0) {
-        throw new Error("Empty string is not allowed as column name");
-    }
-    for (const ch of name){
-        switch(ch){
-            case "?":
-            case ".":
-            case ",":
-            case "'":
-            case '"':
-            case "\\":
-            case "/":
-            case ":":
-            case ")":
-            case "(":
-            case "+":
-            case "-":
-            case "*":
-            case "%":
-            case "~":
-            case "\u0000":
-            case "\u0001":
-            case "\u0002":
-            case "\u0003":
-            case "\u0004":
-            case "\u0005":
-            case "\u0006":
-            case "\u0007":
-            case "\u0008":
-            case "\u0009":
-            case "\u000B":
-            case "\u000c":
-            case "\r":
-            case "\n":
-            case "\u000e":
-            case "\u000f":
-            case "\u007f":
-            case "\ufeff":
-                throw new Error(`Invalid character in column name: ${ch}`);
-        }
-    }
-}
-
-// @ts-check
-// Default maximum length for table and column names.
-const DEFAULT_MAX_NAME_LENGTH = 127;
-/**
- * Abstract base class for SenderBuffer implementations. <br>
- * Provides common functionality for writing data into the buffer.
- */ class SenderBufferBase {
-    /**
-   * Creates an instance of SenderBufferBase.
-   *
-   * @param {SenderOptions} options - Sender configuration object. <br>
-   * See SenderOptions documentation for detailed description of configuration options.
-   */ constructor(options){
-        this.log = options && typeof options.log === "function" ? options.log : log;
-        SenderOptions.resolveDeprecated(options, this.log);
-        this.maxNameLength = options && isInteger(options.max_name_len, 1) ? options.max_name_len : DEFAULT_MAX_NAME_LENGTH;
-        this.maxBufferSize = options && isInteger(options.max_buf_size, 1) ? options.max_buf_size : DEFAULT_MAX_BUFFER_SIZE;
-        this.resize(options && isInteger(options.init_buf_size, 1) ? options.init_buf_size : DEFAULT_BUFFER_SIZE);
-        this.reset();
-    }
-    /**
-   * @ignore
-   * Resizes the buffer. <br>
-   * Can be used to increase the size of the buffer if data to be written would not fit.
-   * Creates a new buffer, and copies the content of the old buffer into the new one.
-   *
-   * @param {number} bufferSize - New size of the buffer used by the sender, provided in bytes
-   * @throws Error if the requested buffer size exceeds the maximum allowed size
-   */ resize(bufferSize) {
-        if (bufferSize > this.maxBufferSize) {
-            throw new Error(`Max buffer size is ${this.maxBufferSize} bytes, requested buffer size: ${bufferSize}`);
-        }
-        this.bufferSize = bufferSize;
-        const newBuffer = node_buffer.Buffer.alloc(this.bufferSize, 0);
-        if (this.buffer) {
-            this.buffer.copy(newBuffer);
-        }
-        this.buffer = newBuffer;
-    }
-    /**
-   * Resets the buffer, data sitting in the buffer will be lost. <br>
-   * In other words it clears the buffer, and sets the writing position to the beginning of the buffer.
-   *
-   * @return {SenderBuffer} Returns with a reference to this buffer.
-   */ reset() {
-        this.position = 0;
-        this.startNewRow();
-        return this;
-    }
-    startNewRow() {
-        this.endOfLastRow = this.position;
-        this.hasTable = false;
-        this.hasSymbols = false;
-        this.hasColumns = false;
-    }
-    /**
-   * @return {Buffer} Returns a cropped buffer, or null if there is nothing to send. <br>
-   * The returned buffer is backed by this buffer instance, meaning the view can change as the buffer is mutated.
-   * Used only in tests to assert the buffer's content.
-   */ toBufferView(pos = this.endOfLastRow) {
-        return pos > 0 ? this.buffer.subarray(0, pos) : null;
-    }
-    /**
-   * @return {Buffer} Returns a cropped buffer ready to send to the server, or null if there is nothing to send. <br>
-   * The returned buffer is a copy of this buffer.
-   * It also compacts the buffer.
-   */ toBufferNew(pos = this.endOfLastRow) {
-        if (pos > 0) {
-            const data = node_buffer.Buffer.allocUnsafe(pos);
-            this.buffer.copy(data, 0, 0, pos);
-            this.compact();
-            return data;
-        }
-        return null;
-    }
-    /**
-   * Writes the table name into the buffer.
-   *
-   * @param {string} table - Table name.
-   * @return {SenderBuffer} Returns with a reference to this buffer.
-   */ table(table) {
-        if (typeof table !== "string") {
-            throw new Error(`Table name must be a string, received ${typeof table}`);
-        }
-        if (this.hasTable) {
-            throw new Error("Table name has already been set");
-        }
-        validateTableName(table, this.maxNameLength);
-        this.checkCapacity([
-            table
-        ], table.length);
-        this.writeEscaped(table);
-        this.hasTable = true;
-        return this;
-    }
-    /**
-   * Writes a symbol name and value into the buffer. <br>
-   * Use it to insert into SYMBOL columns.
-   *
-   * @param {string} name - Symbol name.
-   * @param {unknown} value - Symbol value, toString() is called to extract the actual symbol value from the parameter.
-   * @return {SenderBuffer} Returns with a reference to this buffer.
-   */ symbol(name, value) {
-        if (typeof name !== "string") {
-            throw new Error(`Symbol name must be a string, received ${typeof name}`);
-        }
-        if (!this.hasTable || this.hasColumns) {
-            throw new Error("Symbol can be added only after table name is set and before any column added");
-        }
-        const valueStr = value.toString();
-        this.checkCapacity([
-            name,
-            valueStr
-        ], 2 + name.length + valueStr.length);
-        this.write(",");
-        validateColumnName(name, this.maxNameLength);
-        this.writeEscaped(name);
-        this.write("=");
-        this.writeEscaped(valueStr);
-        this.hasSymbols = true;
-        return this;
-    }
-    /**
-   * Writes a string column with its value into the buffer. <br>
-   * Use it to insert into VARCHAR and STRING columns.
-   *
-   * @param {string} name - Column name.
-   * @param {string} value - Column value, accepts only string values.
-   * @return {SenderBuffer} Returns with a reference to this buffer.
-   */ stringColumn(name, value) {
-        this.writeColumn(name, value, ()=>{
-            this.checkCapacity([
-                value
-            ], 2 + value.length);
-            this.write('"');
-            this.writeEscaped(value, true);
-            this.write('"');
-        }, "string");
-        return this;
-    }
-    /**
-   * Writes a boolean column with its value into the buffer. <br>
-   * Use it to insert into BOOLEAN columns.
-   *
-   * @param {string} name - Column name.
-   * @param {boolean} value - Column value, accepts only boolean values.
-   * @return {SenderBuffer} Returns with a reference to this buffer.
-   */ booleanColumn(name, value) {
-        this.writeColumn(name, value, ()=>{
-            this.checkCapacity([], 1);
-            this.write(value ? "t" : "f");
-        }, "boolean");
-        return this;
-    }
-    /**
-   * Writes a 64-bit signed integer into the buffer. <br>
-   * Use it to insert into LONG, INT, SHORT and BYTE columns.
-   *
-   * @param {string} name - Column name.
-   * @param {number} value - Column value, accepts only number values.
-   * @return {SenderBuffer} Returns with a reference to this buffer.
-   * @throws Error if the value is not an integer
-   */ intColumn(name, value) {
-        if (!Number.isInteger(value)) {
-            throw new Error(`Value must be an integer, received ${value}`);
-        }
-        this.writeColumn(name, value, ()=>{
-            const valueStr = value.toString();
-            this.checkCapacity([
-                valueStr
-            ], 1);
-            this.write(valueStr);
-            this.write("i");
-        });
-        return this;
-    }
-    /**
-   * Writes a timestamp column with its value into the buffer. <br>
-   * Use it to insert into TIMESTAMP columns.
-   *
-   * @param {string} name - Column name.
-   * @param {number | bigint} value - Epoch timestamp, accepts numbers or BigInts.
-   * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
-   * @return {SenderBuffer} Returns with a reference to this buffer.
-   */ timestampColumn(name, value, unit = "us") {
-        if (typeof value !== "bigint" && !Number.isInteger(value)) {
-            throw new Error(`Value must be an integer or BigInt, received ${value}`);
-        }
-        this.writeColumn(name, value, ()=>{
-            const valueMicros = timestampToMicros(BigInt(value), unit);
-            const valueStr = valueMicros.toString();
-            this.checkCapacity([
-                valueStr
-            ], 1);
-            this.write(valueStr);
-            this.write("t");
-        });
-        return this;
-    }
-    /**
-   * Closes the row after writing the designated timestamp into the buffer.
-   *
-   * @param {number | bigint} timestamp - Designated epoch timestamp, accepts numbers or BigInts.
-   * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
-   */ at(timestamp, unit = "us") {
-        if (!this.hasSymbols && !this.hasColumns) {
-            throw new Error("The row must have a symbol or column set before it is closed");
-        }
-        if (typeof timestamp !== "bigint" && !Number.isInteger(timestamp)) {
-            throw new Error(`Designated timestamp must be an integer or BigInt, received ${timestamp}`);
-        }
-        const timestampNanos = timestampToNanos(BigInt(timestamp), unit);
-        const timestampStr = timestampNanos.toString();
-        this.checkCapacity([
-            timestampStr
-        ], 2);
-        this.write(" ");
-        this.write(timestampStr);
-        this.write("\n");
-        this.startNewRow();
-    }
-    /**
-   * Closes the row without writing designated timestamp into the buffer. <br>
-   * Designated timestamp will be populated by the server on this record.
-   */ atNow() {
-        if (!this.hasSymbols && !this.hasColumns) {
-            throw new Error("The row must have a symbol or column set before it is closed");
-        }
-        this.checkCapacity([], 1);
-        this.write("\n");
-        this.startNewRow();
-    }
-    /**
-   * Returns the current position of the buffer. <br>
-   * New data will be written into the buffer starting from this position.
-   */ currentPosition() {
-        return this.position;
-    }
-    /**
-   * Checks if the buffer has sufficient capacity for additional data and resizes if needed.
-   * @param data - Array of strings to calculate the required capacity for
-   * @param base - Base number of bytes to add to the calculation
-   */ checkCapacity(data, base = 0) {
-        let length = base;
-        for (const str of data){
-            length += node_buffer.Buffer.byteLength(str, "utf8");
-        }
-        if (this.position + length > this.bufferSize) {
-            let newSize = this.bufferSize;
-            do {
-                newSize += this.bufferSize;
-            }while (this.position + length > newSize)
-            this.resize(newSize);
-        }
-    }
-    /**
-   * @ignore
-   * Compacts the buffer by removing completed rows.
-   * Moves any remaining data to the beginning of the buffer.
-   */ compact() {
-        if (this.endOfLastRow > 0) {
-            this.buffer.copy(this.buffer, 0, this.endOfLastRow, this.position);
-            this.position = this.position - this.endOfLastRow;
-            this.endOfLastRow = 0;
-        }
-    }
-    /**
-   * @ignore
-   * Common logic for writing column data to the buffer.
-   * @param name - Column name
-   * @param value - Column value
-   * @param writeValue - Function to write the value portion to the buffer
-   * @param valueType - Optional expected type for validation
-   */ writeColumn(name, value, writeValue, valueType) {
-        if (typeof name !== "string") {
-            throw new Error(`Column name must be a string, received ${typeof name}`);
-        }
-        if (valueType && typeof value !== valueType) {
-            throw new Error(`Column value must be of type ${valueType}, received ${typeof value}`);
-        }
-        if (!this.hasTable) {
-            throw new Error("Column can be set only after table name is set");
-        }
-        this.checkCapacity([
-            name
-        ], 2 + name.length);
-        this.write(this.hasColumns ? "," : " ");
-        validateColumnName(name, this.maxNameLength);
-        this.writeEscaped(name);
-        this.write("=");
-        writeValue();
-        this.hasColumns = true;
-    }
-    /**
-   * @ignore
-   * Writes string data to the buffer at the current position.
-   * @param data - String data to write
-   */ write(data) {
-        this.position += this.buffer.write(data, this.position);
-    }
-    /**
-   * @ignore
-   * Writes a single byte to the buffer at the current position.
-   * @param data - Byte value to write
-   */ writeByte(data) {
-        this.position = this.buffer.writeInt8(data, this.position);
-    }
-    /**
-   * @ignore
-   * Writes a 32-bit integer to the buffer in little-endian format.
-   * @param data - Integer value to write
-   */ writeInt(data) {
-        this.position = this.buffer.writeInt32LE(data, this.position);
-    }
-    /**
-   * @ignore
-   * Writes a double-precision float to the buffer in little-endian format.
-   * @param data - Double value to write
-   */ writeDouble(data) {
-        this.position = this.buffer.writeDoubleLE(data, this.position);
-    }
-    writeEscaped(data, quoted = false) {
-        for (const ch of data){
-            if (ch > "\\") {
-                this.write(ch);
-                continue;
-            }
-            switch(ch){
-                case " ":
-                case ",":
-                case "=":
-                    if (!quoted) {
-                        this.write("\\");
-                    }
-                    this.write(ch);
-                    break;
-                case "\n":
-                case "\r":
-                    this.write("\\");
-                    this.write(ch);
-                    break;
-                case '"':
-                    if (quoted) {
-                        this.write("\\");
-                    }
-                    this.write(ch);
-                    break;
-                case "\\":
-                    this.write("\\\\");
-                    break;
-                default:
-                    this.write(ch);
-                    break;
-            }
-        }
-    }
-}
-
-// @ts-check
-/**
- * Buffer implementation for protocol version 1.
- * Sends floating point numbers in their text form.
- */ class SenderBufferV1 extends SenderBufferBase {
-    /**
-   * Creates a new SenderBufferV1 instance.
-   *
-   * @param {SenderOptions} options - Sender configuration object. <br>
-   * See SenderOptions documentation for detailed description of configuration options.   */ constructor(options){
-        super(options);
-    }
-    /**
-   * Writes a 64-bit floating point value into the buffer using v1 serialization (text format). <br>
-   * Use it to insert into DOUBLE or FLOAT database columns.
-   *
-   * @param {string} name - Column name.
-   * @param {number} value - Column value, accepts only number values.
-   * @return {Sender} Returns with a reference to this sender.
-   */ floatColumn(name, value) {
-        this.writeColumn(name, value, ()=>{
-            const valueStr = value.toString();
-            this.checkCapacity([
-                valueStr
-            ]);
-            this.write(valueStr);
-        }, "number");
-        return this;
-    }
-    /**
-   * Array columns are not supported in protocol v1.
-   *
-   * @throws Error indicating arrays are not supported in v1
-   */ arrayColumn() {
-        throw new Error("Arrays are not supported in protocol v1");
-    }
-}
-
-// @ts-check
-// Column type constants for protocol v2.
-const COLUMN_TYPE_DOUBLE = 10;
-const COLUMN_TYPE_NULL = 33;
-// Entity type constants for protocol v2.
-const ENTITY_TYPE_ARRAY = 14;
-const ENTITY_TYPE_DOUBLE = 16;
-// ASCII code for equals sign used in binary protocol.
-const EQUALS_SIGN = "=".charCodeAt(0);
-/**
- * Buffer implementation for protocol version 2.
- * Sends floating point numbers in binary form.
- */ class SenderBufferV2 extends SenderBufferBase {
-    /**
-   * Creates a new SenderBufferV2 instance.
-   *
-   * @param {SenderOptions} options - Sender configuration object. <br>
-   * See SenderOptions documentation for detailed description of configuration options.
-   */ constructor(options){
-        super(options);
-    }
-    /**
-   * Writes a 64-bit floating point value into the buffer using v2 serialization (binary format). <br>
-   * Use it to insert into DOUBLE or FLOAT database columns.
-   *
-   * @param {string} name - Column name.
-   * @param {number} value - Column value, accepts only number values.
-   * @returns {Sender} Returns with a reference to this buffer.
-   */ floatColumn(name, value) {
-        this.writeColumn(name, value, ()=>{
-            this.checkCapacity([], 10);
-            this.writeByte(EQUALS_SIGN);
-            this.writeByte(ENTITY_TYPE_DOUBLE);
-            this.writeDouble(value);
-        }, "number");
-        return this;
-    }
-    /**
-   * Write an array column with its values into the buffer using v2 format.
-   *
-   * @param {string} name - Column name
-   * @param {unknown[]} value - Array values to write (currently supports double arrays)
-   * @returns {Sender} Returns with a reference to this buffer.
-   * @throws Error if array validation fails:
-   * - value is not an array
-   * - or the shape of the array is irregular: the length of sub-arrays are different
-   * - or the array is not homogeneous: its elements are not all the same type
-   */ arrayColumn(name, value) {
-        const dimensions = getDimensions(value);
-        const type = validateArray(value, dimensions);
-        // only number arrays and NULL supported for now
-        if (type !== "number" && type !== null) {
-            throw new Error(`Unsupported array type [type=${type}]`);
-        }
-        this.writeColumn(name, value, ()=>{
-            this.checkCapacity([], 3);
-            this.writeByte(EQUALS_SIGN);
-            this.writeByte(ENTITY_TYPE_ARRAY);
-            if (!value) {
-                this.writeByte(COLUMN_TYPE_NULL);
-            } else {
-                this.writeByte(COLUMN_TYPE_DOUBLE);
-                this.writeArray(value, dimensions, type);
-            }
-        });
-        return this;
-    }
-    writeArray(arr, dimensions, type) {
-        this.checkCapacity([], 1 + dimensions.length * 4);
-        this.writeByte(dimensions.length);
-        for(let i = 0; i < dimensions.length; i++){
-            this.writeInt(dimensions[i]);
-        }
-        this.checkCapacity([], SenderBufferV2.arraySize(dimensions, type));
-        this.writeArrayValues(arr, dimensions);
-    }
-    writeArrayValues(arr, dimensions) {
-        if (Array.isArray(arr[0])) {
-            for(let i = 0; i < arr.length; i++){
-                this.writeArrayValues(arr[i], dimensions);
-            }
-        } else {
-            const type = arr[0] !== undefined ? typeof arr[0] : null;
-            switch(type){
-                case "number":
-                    for(let i = 0; i < arr.length; i++){
-                        this.position = this.buffer.writeDoubleLE(arr[i], this.position);
-                    }
-                    break;
-                case null:
-                    break;
-                default:
-                    throw new Error(`Unsupported array type [type=${type}]`);
-            }
-        }
-    }
-    static arraySize(dimensions, type) {
-        let numOfElements = 1;
-        for(let i = 0; i < dimensions.length; i++){
-            numOfElements *= dimensions[i];
-        }
-        switch(type){
-            case "number":
-                return numOfElements * 8;
-            case "boolean":
-                return numOfElements;
-            case "string":
-                // in case of string[] capacity check is done separately for each array element
-                return 0;
-            case null:
-                // empty array
-                return 0;
-            default:
-                throw new Error(`Unsupported array type [type=${type}]`);
-        }
-    }
-}
-
-// @ts-check
-// Default initial buffer size in bytes (64 KB).
-const DEFAULT_BUFFER_SIZE = 65536; //  64 KB
-// Default maximum buffer size in bytes (100 MB).
-const DEFAULT_MAX_BUFFER_SIZE = 104857600; // 100 MB
-/**
- * Factory function to create a SenderBuffer instance based on the protocol version.
- *
- * @param {SenderOptions} options - Sender configuration object. <br>
- * See SenderOptions documentation for detailed description of configuration options.
- *
- * @returns A SenderBuffer instance appropriate for the specified protocol version
- * @throws Error if protocol version is not specified or is unsupported
- */ function createBuffer(options) {
-    switch(options.protocol_version){
-        case PROTOCOL_VERSION_V2:
-            return new SenderBufferV2(options);
-        case PROTOCOL_VERSION_V1:
-            return new SenderBufferV1(options);
-        case PROTOCOL_VERSION_AUTO:
-        case undefined:
-        case null:
-        case "":
-            throw new Error("Provide the 'protocol_version' option, or call 'await SenderOptions.resolveAuto(options)' first");
-        default:
-            throw new Error("Unsupported protocol version: " + options.protocol_version);
-    }
-}
-
-// @ts-check
-const DEFAULT_AUTO_FLUSH_INTERVAL = 1000; // 1 sec
-/** @classdesc
- * The QuestDB client's API provides methods to connect to the database, ingest data, and close the connection. <br>
- * The client supports multiple transport protocols.
- * <p>
- * <b>Transport Options:</b>
- * <ul>
- * <li><b>HTTP</b>: Uses standard HTTP requests for data ingestion. Provides immediate feedback via HTTP response codes.
- * Recommended for most use cases due to superior error handling and debugging capabilities. Uses Undici library by default for high performance.</li>
- * <li><b>HTTPS</b>: Secure HTTP transport with TLS encryption. Same benefits as HTTP but with encrypted communication.
- * Supports certificate validation and custom CA certificates.</li>
- * <li><b>TCP</b>: Direct TCP connection, provides persistent connections. Uses JWK token-based authentication.</li>
- * <li><b>TCPS</b>: Secure TCP transport with TLS encryption.</li>
- * </ul>
- * </p>
- * <p>
- * The client supports authentication. <br>
- * Authentication details can be passed to the Sender in its configuration options. <br>
- * The client supports Basic username/password and Bearer token authentication methods when used with HTTP protocol,
- * and JWK token authentication when ingesting data via TCP. <br>
- * Please, note that authentication is enabled by default in QuestDB Enterprise only. <br>
- * Details on how to configure authentication in the open source version of
- * QuestDB: {@link https://questdb.io/docs/reference/api/ilp/authenticate}
- * </p>
- * <p>
- * The client also supports TLS encryption for both, HTTP and TCP transports to provide a secure connection. <br>
- * Please, note that the open source version of QuestDB does not support TLS, and requires an external reverse-proxy,
- * such as Nginx to enable encryption.
- * </p>
- * <p>
- * The client supports multiple protocol versions for data serialization. Protocol version 1 uses text-based
- * serialization, while version 2 uses binary encoding for doubles and supports array columns for improved
- * performance. The client can automatically negotiate the protocol version with the server when using HTTP/HTTPS
- * by setting the protocol_version to 'auto' (default behavior).
- * </p>
- * <p>
- * The client uses a buffer to store data. It automatically flushes the buffer by sending its content to the server.
- * Auto flushing can be disabled via configuration options to gain control over transactions. Initial and maximum
- * buffer sizes can also be set.
- * </p>
- * <p>
- * It is recommended that the Sender is created by using one of the static factory methods,
- * <i>Sender.fromConfig(configString, extraOptions)</i> or <i>Sender.fromEnv(extraOptions)</i>.
- * If the Sender is created via its constructor, at least the SenderOptions configuration object should be
- * initialized from a configuration string to make sure that the parameters are validated. <br>
- * Detailed description of the Sender's configuration options can be found in
- * the <a href="SenderOptions.html">SenderOptions</a> documentation.
- * </p>
- * <p>
- * <b>Transport Configuration Examples:</b>
- * <ul>
- * <li>HTTP: <i>Sender.fromConfig("http::addr=localhost:9000")</i></li>
- * <li>HTTPS with authentication: <i>Sender.fromConfig("https::addr=localhost:9000;username=admin;password=secret")</i></li>
- * <li>TCP: <i>Sender.fromConfig("tcp::addr=localhost:9009")</i></li>
- * <li>TCPS with authentication: <i>Sender.fromConfig("tcps::addr=localhost:9009;username=user;token=private_key")</i></li>
- * </ul>
- * </p>
- * <p>
- * <b>HTTP Transport Implementation:</b><br>
- * By default, HTTP/HTTPS transport uses the high-performance Undici library for connection management and request handling.
- * For compatibility or specific requirements, you can enable the standard HTTP transport using Node.js built-in modules
- * by setting <i>stdlib_http=on</i> in the configuration string. The standard HTTP transport provides the same functionality
- * but uses Node.js http/https modules instead of Undici.
- * </p>
- * <p>
- * Extra options can be provided to the Sender in the <i>extraOptions</i> configuration object. <br>
- * A custom logging function and a custom HTTP(S) agent can be passed to the Sender in this object. <br>
- * The logger implementation provides the option to direct log messages to the same place where the host application's
- * log is saved. The default logger writes to the console. <br>
- * The custom HTTP(S) agent option becomes handy if there is a need to modify the default options set for the
- * HTTP(S) connections. A popular setting would be disabling persistent connections, in this case an agent can be
- * passed to the Sender with <i>keepAlive</i> set to <i>false</i>. <br>
- * For example: <i>Sender.fromConfig(`http::addr=host:port`, { agent: new undici.Agent({ connect: { keepAlive: false } })})</i> <br>
- * If no custom agent is configured, the Sender will use its own agent which overrides some default values
- * of <i>undici.Agent</i>. The Sender's own agent uses persistent connections with 1 minute idle timeout, pipelines requests default to 1.
- * </p>
- */ class Sender {
-    /**
-   * Creates an instance of Sender.
-   *
-   * @param {SenderOptions} options - Sender configuration object. <br>
-   * See SenderOptions documentation for detailed description of configuration options.
-   */ constructor(options){
-        this.transport = createTransport(options);
-        this.buffer = createBuffer(options);
-        this.log = typeof options.log === "function" ? options.log : log;
-        this.autoFlush = isBoolean(options.auto_flush) ? options.auto_flush : true;
-        this.autoFlushRows = isInteger(options.auto_flush_rows, 0) ? options.auto_flush_rows : this.transport.getDefaultAutoFlushRows();
-        this.autoFlushInterval = isInteger(options.auto_flush_interval, 0) ? options.auto_flush_interval : DEFAULT_AUTO_FLUSH_INTERVAL;
-        this.reset();
-    }
-    /**
-   * Creates a Sender object by parsing the provided configuration string.
-   *
-   * @param {string} configurationString - Configuration string. <br>
-   * @param {object} extraOptions - Optional extra configuration. <br>
-   * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-   * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-   * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-   * Depends on which transport implementation and protocol used, one of the followings expected: <i>undici.Agent</i>, <i>http.Agent</i> or <i>https.Agent</i>.
-   *
-   * @return {Sender} A Sender object initialized from the provided configuration string.
-   */ static async fromConfig(configurationString, extraOptions) {
-        return new Sender(await SenderOptions.fromConfig(configurationString, extraOptions));
-    }
-    /**
-   * Creates a Sender object by parsing the configuration string set in the <b>QDB_CLIENT_CONF</b> environment variable.
-   *
-   * @param {object} extraOptions - Optional extra configuration. <br>
-   * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-   * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-   * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-   * Depends on which transport implementation and protocol used, one of the followings expected: <i>undici.Agent</i>, <i>http.Agent</i> or <i>https.Agent</i>.
-   *
-   * @return {Sender} A Sender object initialized from the <b>QDB_CLIENT_CONF</b> environment variable.
-   */ static async fromEnv(extraOptions) {
-        return new Sender(await SenderOptions.fromConfig(process.env.QDB_CLIENT_CONF, extraOptions));
-    }
-    /**
-   * Resets the sender's buffer, data sitting in the buffer will be lost. <br>
-   * In other words it clears the buffer, and sets the writing position to the beginning of the buffer.
-   *
-   * @return {Sender} Returns with a reference to this sender.
-   */ reset() {
-        this.buffer.reset();
-        this.resetAutoFlush();
-        return this;
-    }
-    /**
-   * Creates a TCP connection to the database.
-   *
-   * @return {Promise<boolean>} Resolves to true if the client is connected.
-   */ connect() {
-        return this.transport.connect();
-    }
-    /**
-   * Sends the content of the sender's buffer to the database and compacts the buffer.
-   * If the last row is not finished it stays in the sender's buffer.
-   *
-   * @return {Promise<boolean>} Resolves to true when there was data in the buffer to send, and it was sent successfully.
-   */ async flush() {
-        const dataToSend = this.buffer.toBufferNew();
-        if (!dataToSend) {
-            return false; // Nothing to send
-        }
-        this.log("debug", `Flushing, number of flushed rows: ${this.pendingRowCount}`);
-        this.resetAutoFlush();
-        await this.transport.send(dataToSend);
-    }
-    /**
-   * Closes the connection to the database. <br>
-   * Data sitting in the Sender's buffer will be lost unless flush() is called before close().
-   */ async close() {
-        const pos = this.buffer.currentPosition();
-        if (pos > 0) {
-            this.log("warn", `Buffer contains data which has not been flushed before closing the sender, and it will be lost [position=${pos}]`);
-        }
-        return this.transport.close();
-    }
-    /**
-   * Writes the table name into the buffer of the sender of the sender.
-   *
-   * @param {string} table - Table name.
-   * @return {Sender} Returns with a reference to this sender.
-   */ table(table) {
-        this.buffer.table(table);
-        return this;
-    }
-    /**
-   * Writes a symbol name and value into the buffer of the sender. <br>
-   * Use it to insert into SYMBOL columns.
-   *
-   * @param {string} name - Symbol name.
-   * @param {unknown} value - Symbol value, toString() is called to extract the actual symbol value from the parameter.
-   * @return {Sender} Returns with a reference to this sender.
-   */ symbol(name, value) {
-        this.buffer.symbol(name, value);
-        return this;
-    }
-    /**
-   * Writes a string column with its value into the buffer of the sender. <br>
-   * Use it to insert into VARCHAR and STRING columns.
-   *
-   * @param {string} name - Column name.
-   * @param {string} value - Column value, accepts only string values.
-   * @return {Sender} Returns with a reference to this sender.
-   */ stringColumn(name, value) {
-        this.buffer.stringColumn(name, value);
-        return this;
-    }
-    /**
-   * Writes a boolean column with its value into the buffer of the sender. <br>
-   * Use it to insert into BOOLEAN columns.
-   *
-   * @param {string} name - Column name.
-   * @param {boolean} value - Column value, accepts only boolean values.
-   * @return {Sender} Returns with a reference to this sender.
-   */ booleanColumn(name, value) {
-        this.buffer.booleanColumn(name, value);
-        return this;
-    }
-    /**
-   * Writes a 64-bit floating point value into the buffer of the sender. <br>
-   * Use it to insert into DOUBLE or FLOAT database columns.
-   *
-   * @param {string} name - Column name.
-   * @param {number} value - Column value, accepts only number values.
-   * @return {Sender} Returns with a reference to this sender.
-   */ floatColumn(name, value) {
-        this.buffer.floatColumn(name, value);
-        return this;
-    }
-    /**
-   * Writes an array column with its values into the buffer of the sender.
-   *
-   * @param {string} name - Column name
-   * @param {unknown[]} value - Array values to write (currently supports double arrays)
-   * @returns {Sender} Returns with a reference to this sender.
-   * @throws Error if arrays are not supported by the buffer implementation, or array validation fails:
-   * - value is not an array
-   * - or the shape of the array is irregular: the length of sub-arrays are different
-   * - or the array is not homogeneous: its elements are not all the same type
-   */ arrayColumn(name, value) {
-        this.buffer.arrayColumn(name, value);
-        return this;
-    }
-    /**
-   * Writes a 64-bit signed integer into the buffer of the sender. <br>
-   * Use it to insert into LONG, INT, SHORT and BYTE columns.
-   *
-   * @param {string} name - Column name.
-   * @param {number} value - Column value, accepts only number values.
-   * @return {Sender} Returns with a reference to this sender.
-   * @throws Error if the value is not an integer
-   */ intColumn(name, value) {
-        this.buffer.intColumn(name, value);
-        return this;
-    }
-    /**
-   * Writes a timestamp column with its value into the buffer of the sender. <br>
-   * Use it to insert into TIMESTAMP columns.
-   *
-   * @param {string} name - Column name.
-   * @param {number | bigint} value - Epoch timestamp, accepts numbers or BigInts.
-   * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
-   * @return {Sender} Returns with a reference to this sender.
-   */ timestampColumn(name, value, unit = "us") {
-        this.buffer.timestampColumn(name, value, unit);
-        return this;
-    }
-    /**
-   * Closes the row after writing the designated timestamp into the buffer of the sender.
-   *
-   * @param {number | bigint} timestamp - Designated epoch timestamp, accepts numbers or BigInts.
-   * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
-   */ async at(timestamp, unit = "us") {
-        this.buffer.at(timestamp, unit);
-        this.pendingRowCount++;
-        this.log("debug", `Pending row count: ${this.pendingRowCount}`);
-        await this.tryFlush();
-    }
-    /**
-   * Closes the row without writing designated timestamp into the buffer of the sender. <br>
-   * Designated timestamp will be populated by the server on this record.
-   */ async atNow() {
-        this.buffer.atNow();
-        this.pendingRowCount++;
-        this.log("debug", `Pending row count: ${this.pendingRowCount}`);
-        await this.tryFlush();
-    }
-    resetAutoFlush() {
-        this.lastFlushTime = Date.now();
-        this.pendingRowCount = 0;
-        this.log("debug", `Pending row count: ${this.pendingRowCount}`);
-    }
-    async tryFlush() {
-        if (this.autoFlush && this.pendingRowCount > 0 && (this.autoFlushRows > 0 && this.pendingRowCount >= this.autoFlushRows || this.autoFlushInterval > 0 && Date.now() - this.lastFlushTime >= this.autoFlushInterval)) {
-            await this.flush();
-        }
-    }
-}
-
-exports.Sender = Sender;
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Thu Aug 07 2025 12:45:55 GMT+0100 (British Summer Time) -
- - - - - diff --git a/docs/interfaces/SenderBuffer.html b/docs/interfaces/SenderBuffer.html new file mode 100644 index 0000000..e4118b1 --- /dev/null +++ b/docs/interfaces/SenderBuffer.html @@ -0,0 +1,83 @@ +SenderBuffer | QuestDB Node.js Client - v4.0.0

Interface SenderBuffer

Buffer used by the Sender for data serialization.
+Provides methods for writing different data types into the buffer.

+
interface SenderBuffer {
    reset(): SenderBuffer;
    toBufferView(pos?: number): Buffer;
    toBufferNew(pos?: number): Buffer<ArrayBufferLike>;
    table(table: string): SenderBuffer;
    symbol(name: string, value: unknown): SenderBuffer;
    stringColumn(name: string, value: string): SenderBuffer;
    booleanColumn(name: string, value: boolean): SenderBuffer;
    floatColumn(name: string, value: number): SenderBuffer;
    arrayColumn(name: string, value: unknown[]): SenderBuffer;
    intColumn(name: string, value: number): SenderBuffer;
    timestampColumn(
        name: string,
        value: number | bigint,
        unit: TimestampUnit,
    ): SenderBuffer;
    at(timestamp: number | bigint, unit: TimestampUnit): void;
    atNow(): void;
    currentPosition(): number;
}
Index

Methods

  • Resets the buffer, data sitting in the buffer will be lost. +In other words it clears the buffer, and sets the writing position to the beginning of the buffer.

    +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Returns a cropped buffer, or null if there is nothing to send. +The returned buffer is backed by this buffer instance, meaning the view can change as the buffer is mutated. +Used only in tests to assert the buffer's content.

    +

    Parameters

    • Optionalpos: number

      Optional position parameter

      +

    Returns Buffer

    A view of the buffer

    +
  • Returns a cropped buffer ready to send to the server, or null if there is nothing to send. +The returned buffer is a copy of this buffer. +It also compacts the buffer.

    +

    Parameters

    • Optionalpos: number

      Optional position parameter

      +

    Returns Buffer<ArrayBufferLike>

    A copy of the buffer ready to send, or null

    +
  • Writes a symbol name and value into the buffer. +Use it to insert into SYMBOL columns.

    +

    Parameters

    • name: string

      Symbol name.

      +
    • value: unknown

      Symbol value, toString() is called to extract the actual symbol value from the parameter.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a string column with its value into the buffer. +Use it to insert into VARCHAR and STRING columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: string

      Column value, accepts only string values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a boolean column with its value into the buffer. +Use it to insert into BOOLEAN columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: boolean

      Column value, accepts only boolean values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes a 64-bit floating point value into the buffer. +Use it to insert into DOUBLE or FLOAT database columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number

      Column value, accepts only number values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Writes an array column with its values into the buffer.

    +

    Parameters

    • name: string

      Column name

      +
    • value: unknown[]

      Array values to write (currently supports double arrays)

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +

    Error if arrays are not supported by the buffer implementation, or array validation fails:

    +
      +
    • value is not an array
    • +
    • or the shape of the array is irregular: the length of sub-arrays are different
    • +
    • or the array is not homogeneous: its elements are not all the same type
    • +
    +
  • Writes a 64-bit signed integer into the buffer. +Use it to insert into LONG, INT, SHORT and BYTE columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number

      Column value, accepts only number values.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +

    Error if the value is not an integer

    +
  • Writes a timestamp column with its value into the buffer. +Use it to insert into TIMESTAMP columns.

    +

    Parameters

    • name: string

      Column name.

      +
    • value: number | bigint

      Epoch timestamp, accepts numbers or BigInts.

      +
    • unit: TimestampUnit

      Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds.

      +

    Returns SenderBuffer

    Returns with a reference to this buffer.

    +
  • Closes the row after writing the designated timestamp into the buffer.

    +

    Parameters

    • timestamp: number | bigint

      Designated epoch timestamp, accepts numbers or BigInts.

      +
    • unit: TimestampUnit

      Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds.

      +

    Returns void

  • Closes the row without writing designated timestamp into the buffer. +Designated timestamp will be populated by the server on this record.

    +

    Returns void

  • Returns the current position of the buffer. +New data will be written into the buffer starting from this position.

    +

    Returns number

    The current write position in the buffer

    +
diff --git a/docs/interfaces/SenderOptions.html b/docs/interfaces/SenderOptions.html new file mode 100644 index 0000000..0283cd1 --- /dev/null +++ b/docs/interfaces/SenderOptions.html @@ -0,0 +1,128 @@ +SenderOptions | QuestDB Node.js Client - v4.0.0

Interface SenderOptions

Sender configuration options. +
+Properties of the object are initialized through a configuration string.
+The configuration string has the following format: &ltprotocol&gt::&ltkey&gt=&ltvalue>&ltkey&gt=&ltvalue>...;
+The keys are case-sensitive, the trailing semicolon is optional.
+The values are validated and an error is thrown if the format is invalid.
+
+Connection and protocol options

+
    +
  • protocol: enum, accepted values: http, https, tcp, tcps - The protocol used to communicate with the server.
    +When https or tcps used, the connection is secured with TLS encryption. +
  • +
  • protocol_version: enum, accepted values: auto, 1, 2 - The protocol version used for data serialization.
    +Version 1 uses text-based serialization for all data types. Version 2 uses binary encoding for doubles and arrays.
    +When set to 'auto' (default for HTTP/HTTPS), the client automatically negotiates the highest supported version with the server.
    +TCP/TCPS connections default to version 1. +
  • +
  • addr: string - Hostname and port, separated by colon. This key is mandatory, but the port part is optional.
    +If no port is specified, a default will be used.
    +When the protocol is HTTP/HTTPS, the port defaults to 9000. When the protocol is TCP/TCPS, the port defaults to 9009.
    +
    +Examples: http::addr=localhost:9000, https::addr=localhost:9000, http::addr=localhost, tcp::addr=localhost:9009 +
  • +
+
+Authentication options +
    +
  • username: string - Used for authentication.
    +For HTTP, Basic Authentication requires the password option.
    +For TCP with JWK token authentication, token option is required. +
  • +
  • password: string - Password for HTTP Basic authentication, should be accompanied by the username option. +
  • +
  • token: string - For HTTP with Bearer authentication, this is the bearer token.
    +For TCP with JWK token authentication, this is the private key part of the JWK token, +and must be accompanied by the username option. +
  • +
+
+TLS options +
    +
  • tls_verify: enum, accepted values: on, unsafe_off - When the HTTPS or TCPS protocols are selected, TLS encryption is used.
    +By default, the Sender will verify the server's certificate, but this check can be disabled by setting this option to unsafe_off.
    +This is useful in non-production environments where self-signed certificates might be used, but should be avoided in production if possible. +
  • +
  • tls_ca: string - Path to a file containing the root CA's certificate in PEM format.
    +Can be useful when self-signed certificates are used, otherwise should not be set. +
  • +
+
+Auto flush options +
    +
  • auto_flush: enum, accepted values: on, off - The Sender automatically flushes the buffer by default. This can be switched off +by setting this option to off.
    +When disabled, the flush() method of the Sender has to be called explicitly to make sure data is sent to the server.
    +Manual buffer flushing can be useful, especially when we want to control transaction boundaries.
    +When the HTTP protocol is used, each flush results in a single HTTP request, which becomes a single transaction on the server side.
    +The transaction either succeeds, and all rows sent in the request are inserted; or it fails, and none of the rows make it into the database. +
  • +
  • auto_flush_rows: integer - The number of rows that will trigger a flush. When set to 0, row-based flushing is disabled.
    +The Sender will default this parameter to 75000 rows when HTTP protocol is used, and to 600 in case of TCP protocol. +
  • +
  • auto_flush_interval: integer - The number of milliseconds that will trigger a flush, default value is 1000. +When set to 0, interval-based flushing is disabled.
    +Note that the setting is checked only when a new row is added to the buffer. There is no timer registered to flush the buffer automatically. +
  • +
+
+Buffer sizing options +
    +
  • init_buf_size: integer - Initial buffer size, defaults to 64 KiB in the Sender. +
  • +
  • max_buf_size: integer - Maximum buffer size, defaults to 100 MiB in the Sender.
    +If the buffer would need to be extended beyond the maximum size, an error is thrown. +
  • +
+
+HTTP request specific options +
    +
  • request_timeout: integer - The time in milliseconds to wait for a response from the server, set to 10 seconds by default.
    +This is in addition to the calculation derived from the request_min_throughput parameter. +
  • +
  • request_min_throughput: integer - Minimum expected throughput in bytes per second for HTTP requests, set to 100 KiB/s seconds by default.
    +If the throughput is lower than this value, the connection will time out. This is used to calculate an additional +timeout on top of request_timeout. This is useful for large requests. You can set this value to 0 to disable this logic. +
  • +
  • retry_timeout: integer - The time in milliseconds to continue retrying after a failed HTTP request, set to 10 seconds by default.
    +The interval between retries is an exponential backoff starting at 10ms and doubling after each failed attempt up to a maximum of 1 second. +
  • +
+
+Other options +
    +
  • stdlib_http: enum, accepted values: on, off - With HTTP protocol the Undici library is used by default. By setting this option +to on the client switches to node's core http and https modules. +
  • +
  • max_name_len: integer - The maximum length of a table or column name, the Sender defaults this parameter to 127.
    +Recommended to use the same setting as the server, which also uses 127 by default. +
  • +
interface SenderOptions {
    protocol: string;
    protocol_version?: string;
    addr?: string;
    host?: string;
    port?: number;
    username?: string;
    password?: string;
    token?: string;
    token_x?: string;
    token_y?: string;
    auto_flush?: boolean;
    auto_flush_rows?: number;
    auto_flush_interval?: number;
    request_min_throughput?: number;
    request_timeout?: number;
    retry_timeout?: number;
    init_buf_size?: number;
    max_buf_size?: number;
    tls_verify?: boolean;
    tls_ca?: PathOrFileDescriptor;
    tls_roots?: never;
    tls_roots_password?: never;
    max_name_len?: number;
    log?: Logger;
    agent?: Agent | Agent | Agent;
    stdlib_http?: boolean;
    auth?: {
        username?: string;
        keyId?: string;
        password?: string;
        token?: string;
    };
    jwk?: Record<string, string>;
}
Index

Properties

protocol: string
protocol_version?: string
addr?: string
host?: string
port?: number
username?: string
password?: string
token?: string
token_x?: string
token_y?: string
auto_flush?: boolean
auto_flush_rows?: number
auto_flush_interval?: number
request_min_throughput?: number
request_timeout?: number
retry_timeout?: number
init_buf_size?: number
max_buf_size?: number
tls_verify?: boolean
tls_ca?: PathOrFileDescriptor
tls_roots?: never
tls_roots_password?: never
max_name_len?: number
log?: Logger
agent?: Agent | Agent | Agent
stdlib_http?: boolean
auth?: { username?: string; keyId?: string; password?: string; token?: string }
jwk?: Record<string, string>
diff --git a/docs/interfaces/SenderTransport.html b/docs/interfaces/SenderTransport.html new file mode 100644 index 0000000..570177f --- /dev/null +++ b/docs/interfaces/SenderTransport.html @@ -0,0 +1,18 @@ +SenderTransport | QuestDB Node.js Client - v4.0.0

Interface SenderTransport

Interface for QuestDB transport implementations.
+Defines the contract for different transport protocols (HTTP/HTTPS/TCP/TCPS).

+
interface SenderTransport {
    connect(): Promise<boolean>;
    send(data: Buffer): Promise<boolean>;
    close(): Promise<void>;
    getDefaultAutoFlushRows(): number;
}

Implemented by

Index

Methods

  • Establishes a connection to the database server. +Should not be called on HTTP transports.

    +

    Returns Promise<boolean>

    Promise resolving to true if connection is successful

    +
  • Sends the data to the database server.

    +

    Parameters

    • data: Buffer

      Buffer containing the data to send

      +

    Returns Promise<boolean>

    Promise resolving to true if data was sent successfully

    +
  • Closes the connection to the database server. +Should not be called on HTTP transports.

    +

    Returns Promise<void>

    Promise that resolves when the connection is closed

    +
  • Gets the default number of rows that trigger auto-flush for this transport.

    +

    Returns number

    Default auto-flush row count

    +
diff --git a/docs/module-@questdb_nodejs-client.html b/docs/module-@questdb_nodejs-client.html deleted file mode 100644 index 9c04369..0000000 --- a/docs/module-@questdb_nodejs-client.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - JSDoc: Module: @questdb/nodejs-client - - - - - - - - - -
-

Module: @questdb/nodejs-client

- -
-
- -
-
-
A Node.js client for QuestDB.
- -
-
Source:
-
- -
-
-
-
-
-
- - - -
- -
- Documentation generated by - JSDoc 4.0.2 on Wed Apr 17 - 2024 03:38:43 GMT+0100 (British Summer Time) -
- - - - - diff --git a/docs/modules.html b/docs/modules.html new file mode 100644 index 0000000..9982468 --- /dev/null +++ b/docs/modules.html @@ -0,0 +1,2 @@ +QuestDB Node.js Client - v4.0.0
diff --git a/docs/options.js.html b/docs/options.js.html deleted file mode 100644 index 92b46d6..0000000 --- a/docs/options.js.html +++ /dev/null @@ -1,469 +0,0 @@ - - - - - JSDoc: Source: options.js - - - - - - - - - -
-

Source: options.js

- -
-
-
'use strict';
-
-const http = require('http');
-const https = require('https');
-
-const HTTP_PORT = 9000;
-const TCP_PORT = 9009;
-
-const HTTP = 'http';
-const HTTPS = 'https';
-const TCP = 'tcp';
-const TCPS = 'tcps';
-
-const ON = 'on';
-const OFF = 'off';
-const UNSAFE_OFF = 'unsafe_off';
-
-/** @classdesc
- * <a href="Sender.html">Sender</a> configuration options. <br>
- * <br>
- * Properties of the object are initialized through a configuration string. <br>
- * The configuration string has the following format: <i>&ltprotocol&gt::&ltkey&gt=&ltvalue&gt;&ltkey&gt=&ltvalue&gt;...;</i> <br>
- * The keys are case-sensitive, the trailing semicolon is optional. <br>
- * The values are validated, and an error is thrown if the format is invalid. <br>
- * <br>
- * Connection and protocol options
- * <ul>
- * <li> <b>protocol</b>: <i>enum, accepted values: http, https, tcp, tcps</i> - The protocol used to communicate with the server. <br>
- * When <i>https</i> or <i>tcps</i> used, the connection is secured with TLS encryption.
- * </li>
- * <li> addr: <i>string</i> - Hostname and port, separated by colon. This key is mandatory, but the port part is optional. <br>
- * If no port is specified, a default will be used. <br>
- * When the protocol is HTTP/HTTPS, the port defaults to 9000. When the protocol is TCP/TCPS, the port defaults to 9009. <br>
- * <br>
- * Examples: <i>http::addr=localhost:9000</i>, <i>https::addr=localhost:9000</i>, <i>http::addr=localhost</i>, <i>tcp::addr=localhost:9009</i>
- * </li>
- * </ul>
- * <br>
- * Authentication options
- * <ul>
- * <li> username: <i>string</i> - Used for authentication. <br>
- * For HTTP, Basic Authentication requires the <i>password</i> option. <br>
- * For TCP with JWK token authentication, <i>token</i> option is required.
- * </li>
- * <li> password: <i>string</i> - Password for HTTP Basic authentication, should be accompanied by the <i>username</i> option.
- * </li>
- * <li> token: <i>string</i> - For HTTP with Bearer authentication, this is the bearer token. <br>
- * For TCP with JWK token authentication, this is the private key part of the JWK token,
- * and must be accompanied by the <i>username</i> option.
- * </li>
- * </ul>
- * <br>
- * TLS options
- * <ul>
- * <li> tls_verify: <i>enum, accepted values: on, unsafe_off</i> - When the HTTPS or TCPS protocols are selected, TLS encryption is used. <br>
- * By default, the Sender will verify the server's certificate, but this check can be disabled by setting this option to <i>off</i>. This is useful
- * non-production environments where self-signed certificates might be used, but should be avoided in production if possible.
- * </li>
- * <li> tls_ca: <i>string</i> - Path to a file containing the root CA's certificate in PEM format. <br>
- * Can be useful when self-signed certificates are used, otherwise should not be set.
- * </li>
- * </ul>
- * <br>
- * Auto flush options
- * <ul>
- * <li> auto_flush: <i>enum, accepted values: on, off</i> - The Sender automatically flushes the buffer by default. This can be switched off
- * by setting this option to <i>off</i>. <br>
- * When disabled, the flush() method of the Sender has to be called explicitly to make sure data is sent to the server. <br>
- * Manual buffer flushing can be useful, especially when we want to use transactions. When the HTTP protocol is used, each flush results in a single HTTP
- * request, which becomes a single transaction on the server side. The transaction either succeeds, and all rows sent in the request are
- * inserted; or it fails, and none of the rows make it into the database.
- * </li>
- * <li> auto_flush_rows: <i>integer</i> - The number of rows that will trigger a flush. When set to 0, row-based flushing is disabled. <br>
- * The Sender will default this parameter to 75000 rows when HTTP protocol is used, and to 600 in case of TCP protocol.
- * </li>
- * <li> auto_flush_interval: <i>integer</i> - The number of milliseconds that will trigger a flush, default value is 1000.
- * When set to 0, interval-based flushing is disabled. <br>
- * Note that the setting is checked only when a new row is added to the buffer. There is no timer registered to flush the buffer automatically.
- * </li>
- * </ul>
- * <br>
- * Buffer sizing options
- * <ul>
- * <li> init_buf_size: <i>integer</i> - Initial buffer size, defaults to 64 KiB in the Sender.
- * </li>
- * <li> max_buf_size: <i>integer</i> - Maximum buffer size, defaults to 100 MiB in the Sender. <br>
- * If the buffer would need to be extended beyond the maximum size, an error is thrown.
- * </li>
- * </ul>
- * <br>
- * HTTP request specific options
- * <ul>
- * <li> request_timeout: <i>integer</i> - The time in milliseconds to wait for a response from the server, set to 10 seconds by default. <br>
- * This is in addition to the calculation derived from the <i>request_min_throughput</i> parameter.
- * </li>
- * <li> request_min_throughput: <i>integer</i> - Minimum expected throughput in bytes per second for HTTP requests, set to 100 KiB/s seconds by default. <br>
- * If the throughput is lower than this value, the connection will time out. This is used to calculate an additional
- * timeout on top of <i>request_timeout</i>. This is useful for large requests. You can set this value to 0 to disable this logic.
- * </li>
- * <li> retry_timeout: <i>integer</i> - The time in milliseconds to continue retrying after a failed HTTP request, set to 10 seconds by default. <br>
- * The interval between retries is an exponential backoff starting at 10ms and doubling after each failed attempt up to a maximum of 1 second.
- * </li>
- * </ul>
- * <br>
- * Other options
- * <ul>
- * <li> max_name_len: <i>integer</i> - The maximum length of a table or column name, the Sender defaults this parameter to 127. <br>
- * Recommended to use the same setting as the server, which also uses 127 by default.
- * </li>
- * <li> copy_buffer: <i>enum, accepted values: on, off</i> - By default, the Sender creates a new buffer for every flush() call,
- * and the data to be sent to the server is copied into this new buffer.
- * Setting the flag to <i>off</i> results in reusing the same buffer instance for each flush() call. <br>
- * Use this flag only if calls to the client are serialised.
- * </li>
- * </ul>
- */
-class SenderOptions {
-
-    protocol;
-    addr;
-    host; // derived from addr
-    port; // derived from addr
-
-    // replaces `auth` and `jwk` options
-    username;
-    password;
-    token;
-    token_x; // allowed, but ignored
-    token_y; // allowed, but ignored
-
-    auto_flush;
-    auto_flush_rows;
-    auto_flush_interval;
-
-    // replaces `copyBuffer` option
-    copy_buffer;
-
-    request_min_throughput;
-    request_timeout;
-    retry_timeout;
-
-    // replaces `bufferSize` option
-    init_buf_size;
-    max_buf_size;
-
-    tls_verify;
-    tls_ca;
-    tls_roots;          // not supported
-    tls_roots_password; // not supported
-
-    max_name_len;
-
-    log;
-    agent;
-
-    /**
-     * Creates a Sender options object by parsing the provided configuration string.
-     *
-     * @param {string} configurationString - Configuration string. <br>
-     * @param {object} extraOptions - Optional extra configuration. <br>
-     * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-     * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-     * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-     * A <i>http.Agent</i> or <i>https.Agent</i> object is expected.
-     */
-    constructor(configurationString, extraOptions = undefined) {
-        parseConfigurationString(this, configurationString);
-
-        if (extraOptions) {
-            if (extraOptions.log && typeof extraOptions.log !== 'function') {
-                throw new Error('Invalid logging function');
-            }
-            this.log = extraOptions.log;
-
-            if (extraOptions.agent && !(extraOptions.agent instanceof http.Agent) && !(extraOptions.agent instanceof https.Agent)) {
-                throw new Error('Invalid http/https agent');
-            }
-            this.agent = extraOptions.agent;
-        }
-    }
-
-    /**
-     * Creates a Sender options object by parsing the provided configuration string.
-     *
-     * @param {string} configurationString - Configuration string. <br>
-     * @param {object} extraOptions - Optional extra configuration. <br>
-     * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-     * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-     * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-     * A <i>http.Agent</i> or <i>https.Agent</i> object is expected.
-     *
-     * @return {SenderOptions} A Sender configuration object initialized from the provided configuration string.
-     */
-    static fromConfig(configurationString, extraOptions = undefined) {
-        return new SenderOptions(configurationString, extraOptions);
-    }
-
-    /**
-     * Creates a Sender options object by parsing the configuration string set in the <b>QDB_CLIENT_CONF</b> environment variable.
-     *
-     * @param {object} extraOptions - Optional extra configuration. <br>
-     * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-     * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-     * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-     * A <i>http.Agent</i> or <i>https.Agent</i> object is expected.
-     *
-     * @return {SenderOptions} A Sender configuration object initialized from the <b>QDB_CLIENT_CONF</b> environment variable.
-     */
-    static fromEnv(extraOptions = undefined) {
-        return SenderOptions.fromConfig(process.env.QDB_CLIENT_CONF, extraOptions);
-    }
-}
-
-function parseConfigurationString(options, configString) {
-    if (!configString) {
-        throw new Error('Configuration string is missing or empty');
-    }
-
-    const position = parseProtocol(options, configString);
-    parseSettings(options, configString, position);
-    parseAddress(options);
-    parseBufferSizes(options);
-    parseAutoFlushOptions(options);
-    parseTlsOptions(options);
-    parseRequestTimeoutOptions(options);
-    parseMaxNameLength(options);
-    parseCopyBuffer(options);
-}
-
-function parseSettings(options, configString, position) {
-    let index = configString.indexOf(';', position);
-    while (index > -1) {
-        if (index + 1 < configString.length && configString.charAt(index + 1) === ';') {
-            index = configString.indexOf(';', index + 2);
-            continue;
-        }
-
-        parseSetting(options, configString, position, index);
-
-        position = index + 1;
-        index = configString.indexOf(';', position);
-    }
-    if (position < configString.length) {
-        parseSetting(options, configString, position, configString.length);
-    }
-}
-
-function parseSetting(options, configString, position, index) {
-    const setting = configString.slice(position, index).replaceAll(';;', ';');
-    const equalsIndex = setting.indexOf('=');
-    if (equalsIndex < 0) {
-        throw new Error(`Missing '=' sign in '${setting}'`);
-    }
-    const key = setting.slice(0, equalsIndex);
-    const value = setting.slice(equalsIndex + 1);
-    validateConfigKey(key);
-    validateConfigValue(key, value);
-    options[key] = value;
-}
-
-const ValidConfigKeys = [
-    'addr',
-    'username', 'password', 'token', 'token_x', 'token_y',
-    'auto_flush', 'auto_flush_rows', 'auto_flush_interval',
-    'copy_buffer',
-    'request_min_throughput', 'request_timeout', 'retry_timeout',
-    'init_buf_size', 'max_buf_size',
-    'max_name_len',
-    'tls_verify', 'tls_ca', 'tls_roots', 'tls_roots_password'
-];
-
-function validateConfigKey(key) {
-    if (!ValidConfigKeys.includes(key)) {
-        throw new Error(`Unknown configuration key: '${key}'`);
-    }
-}
-
-function validateConfigValue(key, value) {
-    if (!value) {
-        throw new Error(`Invalid configuration, value is not set for '${key}'`);
-    }
-    for (let i = 0; i < value.length; i++) {
-        const unicode = value.codePointAt(i);
-        if (unicode < 0x20 || (unicode > 0x7E && unicode < 0xA0)) {
-            throw new Error(`Invalid configuration, control characters are not allowed: '${value}'`);
-        }
-    }
-}
-
-function parseProtocol(options, configString) {
-    let index = configString.indexOf('::');
-    if (index < 0) {
-        throw new Error('Missing protocol, configuration string format: \'protocol::key1=value1;key2=value2;key3=value3;\'');
-    }
-
-    options.protocol = configString.slice(0, index);
-    switch (options.protocol) {
-        case HTTP:
-        case HTTPS:
-        case TCP:
-        case TCPS:
-            break;
-        default:
-            throw new Error(`Invalid protocol: '${options.protocol}', accepted protocols: 'http', 'https', 'tcp', 'tcps'`);
-    }
-    return index + 2;
-}
-
-function parseAddress(options) {
-    if (!options.addr) {
-        throw new Error('Invalid configuration, \'addr\' is required');
-    }
-
-    const index = options.addr.indexOf(':');
-    if (index < 0) {
-        options.host = options.addr;
-        switch (options.protocol) {
-            case HTTP:
-            case HTTPS:
-                options.port = HTTP_PORT;
-                return;
-            case TCP:
-            case TCPS:
-                options.port = TCP_PORT;
-                return;
-            default:
-                throw new Error(`Invalid protocol: '${options.protocol}', accepted protocols: 'http', 'https', 'tcp', 'tcps'`);
-        }
-    }
-
-    options.host = options.addr.slice(0, index);
-    if (!options.host) {
-        throw new Error(`Host name is required`);
-    }
-
-    const portStr = options.addr.slice(index + 1);
-    if (!portStr) {
-        throw new Error(`Port is required`);
-    }
-    options.port = Number(portStr);
-    if (isNaN(options.port)) {
-        throw new Error(`Invalid port: '${portStr}'`);
-    }
-    if (!Number.isInteger(options.port) || options.port < 1) {
-        throw new Error(`Invalid port: ${options.port}`);
-    }
-}
-
-function parseBufferSizes(options) {
-    parseInteger(options, 'init_buf_size', 'initial buffer size', 1);
-    parseInteger(options, 'max_buf_size', 'max buffer size', 1);
-}
-
-function parseAutoFlushOptions(options) {
-    parseBoolean(options, 'auto_flush', 'auto flush');
-    parseInteger(options, 'auto_flush_rows', 'auto flush rows', 0);
-    parseInteger(options, 'auto_flush_interval', 'auto flush interval', 0);
-}
-
-function parseTlsOptions(options) {
-    parseBoolean(options, 'tls_verify', 'TLS verify', UNSAFE_OFF);
-
-    if (options.tls_roots || options.tls_roots_password) {
-        throw new Error('\'tls_roots\' and \'tls_roots_password\' options are not supported, please, ' +
-            'use the \'tls_ca\' option or the NODE_EXTRA_CA_CERTS environment variable instead');
-    }
-}
-
-function parseRequestTimeoutOptions(options) {
-    parseInteger(options, 'request_min_throughput', 'request min throughput', 1);
-    parseInteger(options, 'request_timeout', 'request timeout', 1);
-    parseInteger(options, 'retry_timeout', 'retry timeout', 0);
-}
-
-function parseMaxNameLength(options) {
-    parseInteger(options, 'max_name_len', 'max name length', 1);
-}
-
-function parseCopyBuffer(options) {
-    parseBoolean(options, 'copy_buffer', 'copy buffer');
-}
-
-function parseBoolean(options, property, description, offValue = OFF) {
-    if (options[property]) {
-        const property_str = options[property];
-        switch (property_str) {
-            case ON:
-                options[property] = true;
-                break;
-            case offValue:
-                options[property] = false;
-                break;
-            default:
-                throw new Error(`Invalid ${description} option: '${property_str}'`);
-        }
-    }
-}
-
-function parseInteger(options, property, description, lowerBound) {
-    if (options[property]) {
-        const property_str = options[property];
-        options[property] = Number(property_str);
-        if (isNaN(options[property])) {
-            throw new Error(`Invalid ${description} option, not a number: '${property_str}'`);
-        }
-        if (!Number.isInteger(options[property]) || options[property] < lowerBound) {
-            throw new Error(`Invalid ${description} option: ${options[property]}`);
-        }
-    }
-}
-
-exports.SenderOptions = SenderOptions;
-exports.HTTP = HTTP;
-exports.HTTPS = HTTPS;
-exports.TCP = TCP;
-exports.TCPS = TCPS;
-
-
-
-
- - - -
- -
- Documentation generated by - JSDoc 4.0.2 on Tue Aug 13 - 2024 14:27:30 GMT+0300 (Eastern European Summer Time) -
- - - - - diff --git a/docs/scripts/linenumber.js b/docs/scripts/linenumber.js deleted file mode 100644 index 4354785..0000000 --- a/docs/scripts/linenumber.js +++ /dev/null @@ -1,25 +0,0 @@ -/*global document */ -(() => { - const source = document.getElementsByClassName('prettyprint source linenums'); - let i = 0; - let lineNumber = 0; - let lineId; - let lines; - let totalLines; - let anchorHash; - - if (source && source[0]) { - anchorHash = document.location.hash.substring(1); - lines = source[0].getElementsByTagName('li'); - totalLines = lines.length; - - for (; i < totalLines; i++) { - lineNumber++; - lineId = `line${lineNumber}`; - lines[i].id = lineId; - if (lineId === anchorHash) { - lines[i].className += ' selected'; - } - } - } -})(); diff --git a/docs/scripts/prettify/Apache-License-2.0.txt b/docs/scripts/prettify/Apache-License-2.0.txt deleted file mode 100644 index d645695..0000000 --- a/docs/scripts/prettify/Apache-License-2.0.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/docs/scripts/prettify/lang-css.js b/docs/scripts/prettify/lang-css.js deleted file mode 100644 index 041e1f5..0000000 --- a/docs/scripts/prettify/lang-css.js +++ /dev/null @@ -1,2 +0,0 @@ -PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", -/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/docs/scripts/prettify/prettify.js b/docs/scripts/prettify/prettify.js deleted file mode 100644 index eef5ad7..0000000 --- a/docs/scripts/prettify/prettify.js +++ /dev/null @@ -1,28 +0,0 @@ -var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; -(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= -[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), -l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, -q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, -q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, -"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), -a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} -for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], -"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], -H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], -J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ -I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), -["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", -/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), -["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", -hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= -!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p - - - - JSDoc: Source: sender.js - - - - - - - - - -
-

Source: sender.js

- -
-
-
'use strict';
-
-/* eslint-disable no-unused-vars */
-
-const { readFileSync } = require("fs");
-const { Buffer } = require('buffer');
-const { log } = require('./logging');
-const { validateTableName, validateColumnName } = require('./validation');
-const { SenderOptions, HTTP, HTTPS, TCP, TCPS } = require('./options');
-const http = require('http');
-const https = require('https');
-const net = require('net');
-const tls = require('tls');
-const crypto = require('crypto');
-
-const HTTP_NO_CONTENT = 204; // success
-
-const DEFAULT_HTTP_AUTO_FLUSH_ROWS = 75000;
-const DEFAULT_TCP_AUTO_FLUSH_ROWS = 600;
-const DEFAULT_AUTO_FLUSH_INTERVAL = 1000; // 1 sec
-
-const DEFAULT_MAX_NAME_LENGTH = 127;
-
-const DEFAULT_REQUEST_MIN_THROUGHPUT = 102400; // 100 KB/sec
-const DEFAULT_REQUEST_TIMEOUT = 10000; // 10 sec
-const DEFAULT_RETRY_TIMEOUT = 10000; // 10 sec
-
-const DEFAULT_BUFFER_SIZE = 65536; //  64 KB
-const DEFAULT_MAX_BUFFER_SIZE = 104857600; // 100 MB
-
-// default options for HTTP agent
-// - persistent connections with 1 minute idle timeout, server side has 5 minutes set by default
-// - max open connections is set to 256, same as server side default
-const DEFAULT_HTTP_AGENT_CONFIG = {
-    maxSockets: 256,
-    keepAlive: true,
-    timeout: 60000 // 1 min
-}
-
-// an arbitrary public key, not used in authentication
-// only used to construct a valid JWK token which is accepted by the crypto API
-const PUBLIC_KEY = {
-    x: 'aultdA0PjhD_cWViqKKyL5chm6H1n-BiZBo_48T-uqc',
-    y: '__ptaol41JWSpTTL525yVEfzmY8A6Vi_QrW1FjKcHMg'
-};
-
-/** @classdesc
- * The QuestDB client's API provides methods to connect to the database, ingest data, and close the connection.
- * The supported protocols are HTTP and TCP. HTTP is preferred as it provides feedback in the HTTP response. <br>
- * Based on benchmarks HTTP also provides higher throughput, if configured to ingest data in bigger batches.
- * <p>
- * The client supports authentication. <br>
- * Authentication details can be passed to the Sender in its configuration options. <br>
- * The client supports Basic username/password and Bearer token authentication methods when used with HTTP protocol,
- * and JWK token authentication when ingesting data via TCP. <br>
- * Please, note that authentication is enabled by default in QuestDB Enterprise only. <br>
- * Details on how to configure authentication in the open source version of
- * QuestDB: {@link https://questdb.io/docs/reference/api/ilp/authenticate}
- * </p>
- * <p>
- * The client also supports TLS encryption for both, HTTP and TCP transports to provide a secure connection. <br>
- * Please, note that the open source version of QuestDB does not support TLS, and requires an external reverse-proxy,
- * such as Nginx to enable encryption.
- * </p>
- * <p>
- * The client uses a buffer to store data. It automatically flushes the buffer by sending its content to the server.
- * Auto flushing can be disabled via configuration options to gain control over transactions. Initial and maximum
- * buffer sizes can also be set.
- * </p>
- * <p>
- * It is recommended that the Sender is created by using one of the static factory methods,
- * <i>Sender.fromConfig(configString, extraOptions)</i> or <i>Sender.fromEnv(extraOptions)</i>).
- * If the Sender is created via its constructor, at least the SenderOptions configuration object should be
- * initialized from a configuration string to make sure that the parameters are validated. <br>
- * Detailed description of the Sender's configuration options can be found in
- * the <a href="SenderOptions.html">SenderOptions</a> documentation.
- * </p>
- * <p>
- * Extra options can be provided to the Sender in the <i>extraOptions</i> configuration object. <br>
- * A custom logging function and a custom HTTP(S) agent can be passed to the Sender in this object. <br>
- * The logger implementation provides the option to direct log messages to the same place where the host application's
- * log is saved. The default logger writes to the console. <br>
- * The custom HTTP(S) agent option becomes handy if there is a need to modify the default options set for the
- * HTTP(S) connections. A popular setting would be disabling persistent connections, in this case an agent can be
- * passed to the Sender with <i>keepAlive</i> set to <i>false</i>. <br>
- * For example: <i>Sender.fromConfig(`http::addr=host:port`, { agent: new http.Agent({ keepAlive: false })})</i> <br>
- * If no custom agent is configured, the Sender will use its own agent which overrides some default values
- * of <i>http.Agent</i>/<i>https.Agent</i>. The Sender's own agent uses persistent connections with 1 minute idle
- * timeout, and limits the number of open connections to the server, which is set to 256 for each host.
- * </p>
- */
-class Sender {
-    /** @private */ static DEFAULT_HTTP_AGENT;
-    /** @private */ static DEFAULT_HTTPS_AGENT;
-
-    /** @private */ http;       // true if the protocol is HTTP/HTTPS, false if it is TCP/TCPS
-    /** @private */ secure;     // true if the protocol is HTTPS or TCPS, false otherwise
-    /** @private */ host;
-    /** @private */ port;
-
-    /** @private */ socket;
-
-    /** @private */ username;
-    /** @private */ password;
-    /** @private */ token;
-
-    /** @private */ tlsVerify;
-    /** @private */ tlsCA;
-
-    /** @private */ bufferSize;
-    /** @private */ maxBufferSize;
-    /** @private */ buffer;
-    /** @private */ toBuffer;
-    /** @private */ doResolve;
-    /** @private */ position;
-    /** @private */ endOfLastRow;
-
-    /** @private */ autoFlush;
-    /** @private */ autoFlushRows;
-    /** @private */ autoFlushInterval;
-    /** @private */ lastFlushTime;
-    /** @private */ pendingRowCount;
-
-    /** @private */ requestMinThroughput;
-    /** @private */ requestTimeout;
-    /** @private */ retryTimeout;
-
-    /** @private */ hasTable;
-    /** @private */ hasSymbols;
-    /** @private */ hasColumns;
-
-    /** @private */ maxNameLength;
-
-    /** @private */ log;
-    /** @private */ agent;
-
-    /**
-     * Creates an instance of Sender.
-     *
-     * @param {SenderOptions} options - Sender configuration object. <br>
-     * See SenderOptions documentation for detailed description of configuration options. <br>
-     */
-    constructor(options) {
-        if (!options || !options.protocol) {
-            throw new Error('The \'protocol\' option is mandatory');
-        }
-        replaceDeprecatedOptions(options);
-
-        this.log = typeof options.log === 'function' ? options.log : log;
-
-        switch (options.protocol) {
-            case HTTP:
-                this.http = true;
-                this.secure = false;
-                this.agent = options.agent instanceof http.Agent ? options.agent : this.getDefaultHttpAgent();
-                break;
-            case HTTPS:
-                this.http = true;
-                this.secure = true;
-                this.agent = options.agent instanceof https.Agent ? options.agent : this.getDefaultHttpsAgent();
-                break;
-            case TCP:
-                this.http = false;
-                this.secure = false;
-                break;
-            case TCPS:
-                this.http = false;
-                this.secure = true;
-                break;
-            default:
-                throw new Error(`Invalid protocol: '${options.protocol}'`);
-        }
-
-        if (this.http) {
-            this.username = options.username;
-            this.password = options.password;
-            this.token = options.token;
-            if (!options.port) {
-                options.port = 9000;
-            }
-        } else {
-            if (!options.auth && !options.jwk) {
-                constructAuth(options);
-            }
-            this.jwk = constructJwk(options);
-            if (!options.port) {
-                options.port = 9009;
-            }
-        }
-
-        this.host = options.host;
-        this.port = options.port;
-
-        this.tlsVerify = isBoolean(options.tls_verify) ? options.tls_verify : true;
-        this.tlsCA = options.tls_ca ? readFileSync(options.tls_ca) : undefined;
-
-        this.autoFlush = isBoolean(options.auto_flush) ? options.auto_flush : true;
-        this.autoFlushRows = isInteger(options.auto_flush_rows, 0) ? options.auto_flush_rows : (this.http ? DEFAULT_HTTP_AUTO_FLUSH_ROWS : DEFAULT_TCP_AUTO_FLUSH_ROWS);
-        this.autoFlushInterval = isInteger(options.auto_flush_interval, 0) ? options.auto_flush_interval : DEFAULT_AUTO_FLUSH_INTERVAL;
-
-        this.maxNameLength = isInteger(options.max_name_len, 1) ? options.max_name_len : DEFAULT_MAX_NAME_LENGTH;
-
-        this.requestMinThroughput = isInteger(options.request_min_throughput, 1) ? options.request_min_throughput : DEFAULT_REQUEST_MIN_THROUGHPUT;
-        this.requestTimeout = isInteger(options.request_timeout, 1) ? options.request_timeout : DEFAULT_REQUEST_TIMEOUT;
-        this.retryTimeout = isInteger(options.retry_timeout, 0) ? options.retry_timeout : DEFAULT_RETRY_TIMEOUT;
-
-        const noCopy = isBoolean(options.copy_buffer) && !options.copy_buffer;
-        this.toBuffer = noCopy ? this.toBufferView : this.toBufferNew;
-        this.doResolve = noCopy
-            ? (resolve) => {
-                compact(this);
-                resolve(true);
-            }
-            : (resolve) => {
-                resolve(true);
-            }
-        this.maxBufferSize = isInteger(options.max_buf_size, 1) ? options.max_buf_size : DEFAULT_MAX_BUFFER_SIZE;
-        this.resize(isInteger(options.init_buf_size, 1) ? options.init_buf_size : DEFAULT_BUFFER_SIZE);
-        this.reset();
-    }
-
-    /**
-     * Creates a Sender options object by parsing the provided configuration string.
-     *
-     * @param {string} configurationString - Configuration string. <br>
-     * @param {object} extraOptions - Optional extra configuration. <br>
-     * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-     * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-     * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-     * A <i>http.Agent</i> or <i>https.Agent</i> object is expected.
-     *
-     * @return {Sender} A Sender object initialized from the provided configuration string.
-     */
-    static fromConfig(configurationString, extraOptions = undefined) {
-        return new Sender(SenderOptions.fromConfig(configurationString, extraOptions));
-    }
-
-    /**
-     * Creates a Sender options object by parsing the configuration string set in the <b>QDB_CLIENT_CONF</b> environment variable.
-     *
-     * @param {object} extraOptions - Optional extra configuration. <br>
-     * - 'log' is a logging function used by the <a href="Sender.html">Sender</a>. <br>
-     * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void</i>. <br>
-     * - 'agent' is a custom http/https agent used by the <a href="Sender.html">Sender</a> when http/https transport is used. <br>
-     * A <i>http.Agent</i> or <i>https.Agent</i> object is expected.
-     *
-     * @return {Sender} A Sender object initialized from the <b>QDB_CLIENT_CONF</b> environment variable.
-     */
-    static fromEnv(extraOptions = undefined) {
-        return new Sender(SenderOptions.fromConfig(process.env.QDB_CLIENT_CONF, extraOptions));
-    }
-
-    /**
-     * Extends the size of the sender's buffer. <br>
-     * Can be used to increase the size of buffer if overflown.
-     * The buffer's content is copied into the new buffer.
-     *
-     * @param {number} bufferSize - New size of the buffer used by the sender, provided in bytes.
-     */
-    resize(bufferSize) {
-        if (bufferSize > this.maxBufferSize) {
-            throw new Error(`Max buffer size is ${this.maxBufferSize} bytes, requested buffer size: ${bufferSize}`);
-        }
-        this.bufferSize = bufferSize;
-        // Allocating an extra byte because Buffer.write() does not fail if the length of the data to be written is
-        // longer than the size of the buffer. It simply just writes whatever it can, and returns.
-        // If we can write into the extra byte, that indicates buffer overflow.
-        // See the check in our write() function.
-        const newBuffer = Buffer.alloc(this.bufferSize + 1, 0, 'utf8');
-        if (this.buffer) {
-            this.buffer.copy(newBuffer);
-        }
-        this.buffer = newBuffer;
-    }
-
-    /**
-     * Resets the buffer, data added to the buffer will be lost. <br>
-     * In other words it clears the buffer and sets the writing position to the beginning of the buffer.
-     *
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    reset() {
-        this.position = 0;
-        this.lastFlushTime = Date.now();
-        this.pendingRowCount = 0;
-        startNewRow(this);
-        return this;
-    }
-
-    /**
-     * Creates a TCP connection to the database.
-     *
-     * @param {net.NetConnectOpts | tls.ConnectionOptions} connectOptions - Connection options, host and port are required.
-     *
-     * @return {Promise<boolean>} Resolves to true if the client is connected.
-     */
-    connect(connectOptions = undefined) {
-        if (this.http) {
-            throw new Error('\'connect()\' should be called only if the sender connects via TCP');
-        }
-
-        if (!connectOptions) {
-            connectOptions = {
-                host: this.host,
-                port: this.port,
-                ca: this.tlsCA
-            }
-        }
-        if (!connectOptions.host) {
-            throw new Error('Hostname is not set');
-        }
-        if (!connectOptions.port) {
-            throw new Error('Port is not set');
-        }
-
-        let self = this;
-        return new Promise((resolve, reject) => {
-            if (this.socket) {
-                throw new Error('Sender connected already');
-            }
-
-            let authenticated = false;
-            let data;
-
-            this.socket = !this.secure
-                ? net.connect(connectOptions)
-                : tls.connect(connectOptions, () => {
-                    if (authenticated) {
-                        resolve(true);
-                    }
-                });
-            this.socket.setKeepAlive(true);
-
-            this.socket.on('data', async raw => {
-                data = !data ? raw : Buffer.concat([data, raw]);
-                if (!authenticated) {
-                    authenticated = await authenticate(self, data);
-                    if (authenticated) {
-                        resolve(true);
-                    }
-                } else {
-                    this.log('warn', `Received unexpected data: ${data}`);
-                }
-            })
-            .on('ready', async () => {
-                this.log('info', `Successfully connected to ${connectOptions.host}:${connectOptions.port}`);
-                if (self.jwk) {
-                    this.log('info', `Authenticating with ${connectOptions.host}:${connectOptions.port}`);
-                    await self.socket.write(`${self.jwk.kid}\n`, err => {
-                        if (err) {
-                            reject(err);
-                        }
-                    });
-                } else {
-                    authenticated = true;
-                    if (!self.secure || !self.tlsVerify) {
-                        resolve(true);
-                    }
-                }
-            })
-            .on('error', err => {
-                self.log('error', err);
-                if (err.code !== 'SELF_SIGNED_CERT_IN_CHAIN' || self.tlsVerify) {
-                    reject(err);
-                }
-            });
-        });
-    }
-
-    /**
-     * @ignore
-     * @return {http.Agent} Returns the default http agent.
-     */
-    getDefaultHttpAgent() {
-        if (!Sender.DEFAULT_HTTP_AGENT) {
-            Sender.DEFAULT_HTTP_AGENT = new http.Agent(DEFAULT_HTTP_AGENT_CONFIG);
-        }
-        return Sender.DEFAULT_HTTP_AGENT;
-    }
-
-    /**
-     * @ignore
-     * @return {https.Agent} Returns the default https agent.
-     */
-    getDefaultHttpsAgent() {
-        if (!Sender.DEFAULT_HTTPS_AGENT) {
-            Sender.DEFAULT_HTTPS_AGENT = new https.Agent(DEFAULT_HTTP_AGENT_CONFIG);
-        }
-        return Sender.DEFAULT_HTTPS_AGENT;
-    }
-
-    /**
-     * Closes the TCP connection to the database. <br>
-     * Data sitting in the Sender's buffer will be lost unless flush() is called before close().
-     */
-    async close() {
-        if (this.socket) {
-            const address = this.socket.remoteAddress;
-            const port = this.socket.remotePort;
-            this.socket.destroy();
-            this.socket = null;
-            this.log('info', `Connection to ${address}:${port} is closed`);
-        }
-    }
-
-    /**
-     * Sends the buffer's content to the database and compacts the buffer.
-     * If the last row is not finished it stays in the sender's buffer.
-     *
-     * @return {Promise<boolean>} Resolves to true when there was data in the buffer to send.
-     */
-    async flush() {
-        const data = this.toBuffer(this.endOfLastRow);
-        if (!data) {
-            return false;
-        }
-
-        if (this.http) {
-            const request = this.secure ? https.request : http.request;
-            const options = createRequestOptions(this, data);
-            return sendHttp(this, request, options, data, this.retryTimeout);
-        } else {
-            if (!this.socket) {
-                throw new Error('Sender is not connected');
-            }
-            return sendTcp(this, data);
-        }
-    }
-
-    /**
-     * @ignore
-     * @return {Buffer} Returns a cropped buffer ready to send to the server or null if there is nothing to send.
-     * The returned buffer is backed by the sender's buffer.
-     */
-    toBufferView(pos = this.position) {
-        return pos > 0
-            ? this.buffer.subarray(0, pos)
-            : null;
-    }
-
-    /**
-     * @ignore
-     * @return {Buffer} Returns a cropped buffer ready to send to the server or null if there is nothing to send.
-     * The returned buffer is a copy of the sender's buffer.
-     */
-    toBufferNew(pos = this.position) {
-        if (pos > 0) {
-            const data = Buffer.allocUnsafe(pos);
-            this.buffer.copy(data, 0, 0, pos);
-            compact(this);
-            return data;
-        }
-        return null;
-    }
-
-    /**
-     * Write the table name into the buffer of the sender.
-     *
-     * @param {string} table - Table name.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    table(table) {
-        if (typeof table !== 'string') {
-            throw new Error(`Table name must be a string, received ${typeof table}`);
-        }
-        if (this.hasTable) {
-            throw new Error('Table name has already been set');
-        }
-        validateTableName(table, this.maxNameLength);
-        checkCapacity(this, [table]);
-        writeEscaped(this, table);
-        this.hasTable = true;
-        return this;
-    }
-
-    /**
-     * Write a symbol name and value into the buffer of the sender.
-     *
-     * @param {string} name - Symbol name.
-     * @param {any} value - Symbol value, toString() will be called to extract the actual symbol value from the parameter.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    symbol(name, value) {
-        if (typeof name !== 'string') {
-            throw new Error(`Symbol name must be a string, received ${typeof name}`);
-        }
-        if (!this.hasTable || this.hasColumns) {
-            throw new Error('Symbol can be added only after table name is set and before any column added');
-        }
-        const valueStr = value.toString();
-        checkCapacity(this, [name, valueStr], 2 + name.length + valueStr.length);
-        write(this, ',');
-        validateColumnName(name, this.maxNameLength);
-        writeEscaped(this, name);
-        write(this, '=');
-        writeEscaped(this, valueStr);
-        this.hasSymbols = true;
-        return this;
-    }
-
-    /**
-     * Write a string column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {string} value - Column value, accepts only string values.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    stringColumn(name, value) {
-        writeColumn(this, name, value, () => {
-            checkCapacity(this, [value], 2 + value.length);
-            write(this, '"');
-            writeEscaped(this, value, true);
-            write(this, '"');
-        }, 'string');
-        return this;
-    }
-
-    /**
-     * Write a boolean column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {boolean} value - Column value, accepts only boolean values.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    booleanColumn(name, value) {
-        writeColumn(this, name, value, () => {
-            checkCapacity(this, [], 1);
-            write(this, value ? 't' : 'f');
-        }, 'boolean');
-        return this;
-    }
-
-    /**
-     * Write a float column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {number} value - Column value, accepts only number values.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    floatColumn(name, value) {
-        writeColumn(this, name, value, () => {
-            const valueStr = value.toString();
-            checkCapacity(this, [valueStr], valueStr.length);
-            write(this, valueStr);
-        }, 'number');
-        return this;
-    }
-
-    /**
-     * Write an integer column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {number} value - Column value, accepts only number values.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    intColumn(name, value) {
-        if (!Number.isInteger(value)) {
-            throw new Error(`Value must be an integer, received ${value}`);
-        }
-        writeColumn(this, name, value, () => {
-            const valueStr = value.toString();
-            checkCapacity(this, [valueStr], 1 + valueStr.length);
-            write(this, valueStr);
-            write(this, 'i');
-        });
-        return this;
-    }
-
-    /**
-     * Write a timestamp column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {number | bigint} value - Epoch timestamp, accepts numbers or BigInts.
-     * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    timestampColumn(name, value, unit = 'us') {
-        if (typeof value !== 'bigint' && !Number.isInteger(value)) {
-            throw new Error(`Value must be an integer or BigInt, received ${value}`);
-        }
-        writeColumn(this, name, value, () => {
-            const valueMicros = timestampToMicros(BigInt(value), unit);
-            const valueStr = valueMicros.toString();
-            checkCapacity(this, [valueStr], 1 + valueStr.length);
-            write(this, valueStr);
-            write(this, 't');
-        });
-        return this;
-    }
-
-    /**
-     * Closing the row after writing the designated timestamp into the buffer of the sender.
-     *
-     * @param {number | bigint} timestamp - Designated epoch timestamp, accepts numbers or BigInts.
-     * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
-     */
-    async at(timestamp, unit = 'us') {
-        if (!this.hasSymbols && !this.hasColumns) {
-            throw new Error('The row must have a symbol or column set before it is closed');
-        }
-        if (typeof timestamp !== 'bigint' && !Number.isInteger(timestamp)) {
-            throw new Error(`Designated timestamp must be an integer or BigInt, received ${timestamp}`);
-        }
-        const timestampNanos = timestampToNanos(BigInt(timestamp), unit);
-        const timestampStr = timestampNanos.toString();
-        checkCapacity(this, [], 2 + timestampStr.length);
-        write(this, ' ');
-        write(this, timestampStr);
-        write(this, '\n');
-        this.pendingRowCount++;
-        startNewRow(this);
-        await autoFlush(this);
-    }
-
-    /**
-     * Closing the row without writing designated timestamp into the buffer of the sender. <br>
-     * Designated timestamp will be populated by the server on this record.
-     */
-    async atNow() {
-        if (!this.hasSymbols && !this.hasColumns) {
-            throw new Error('The row must have a symbol or column set before it is closed');
-        }
-        checkCapacity(this, [], 1);
-        write(this, '\n');
-        this.pendingRowCount++;
-        startNewRow(this);
-        await autoFlush(this);
-    }
-}
-
-function isBoolean(value) {
-    return typeof value === 'boolean';
-}
-
-function isInteger(value, lowerBound) {
-    return typeof value === 'number' && Number.isInteger(value) && value >= lowerBound;
-}
-
-async function authenticate(sender, challenge) {
-    // Check for trailing \n which ends the challenge
-    if (challenge.slice(-1).readInt8() === 10) {
-        const keyObject = await crypto.createPrivateKey(
-            {'key': sender.jwk, 'format': 'jwk'}
-        );
-        const signature = await crypto.sign(
-            'RSA-SHA256',
-            challenge.slice(0, challenge.length - 1),
-            keyObject
-        );
-
-        return new Promise((resolve, reject) => {
-            sender.socket.write(`${Buffer.from(signature).toString('base64')}\n`, err => {
-                err ? reject(err) : resolve(true);
-            });
-        });
-    }
-    return false;
-}
-
-function startNewRow(sender) {
-    sender.endOfLastRow = sender.position;
-    sender.hasTable = false;
-    sender.hasSymbols = false;
-    sender.hasColumns = false;
-}
-
-function createRequestOptions(sender, data) {
-    const timeoutMillis = (data.length / sender.requestMinThroughput) * 1000 + sender.requestTimeout;
-    const options = {
-        hostname: sender.host,
-        port: sender.port,
-        agent: sender.agent,
-        path: '/write?precision=n',
-        method: 'POST',
-        timeout: timeoutMillis
-    };
-    if (sender.secure) {
-        options.rejectUnauthorized = sender.tlsVerify;
-        options.ca = sender.tlsCA;
-    }
-    return options;
-}
-
-function sendHttp(sender, request, options, data, retryTimeout, retryBegin = -1, retryInterval = -1) {
-    return new Promise((resolve, reject) => {
-        let statusCode = -1;
-        const req = request(options, response => {
-            statusCode = response.statusCode;
-
-            const body = [];
-            response
-                .on('data', chunk => {
-                    body.push(chunk);
-                })
-                .on('error', err => {
-                    sender.log('error', `resp err=${err}`);
-                });
-
-            if (statusCode === HTTP_NO_CONTENT) {
-                response.on('end', () => {
-                    if (body.length > 0) {
-                        sender.log('warn', `Unexpected message from server: ${Buffer.concat(body)}`);
-                    }
-                    sender.doResolve(resolve);
-                });
-            } else {
-                req.destroy(new Error(`HTTP request failed, statusCode=${statusCode}, error=${Buffer.concat(body)}`));
-            }
-        });
-
-        if (sender.token) {
-            req.setHeader('Authorization', 'Bearer ' + sender.token);
-        } else if (sender.username && sender.password) {
-            req.setHeader('Authorization', 'Basic ' + Buffer.from(sender.username + ':' + sender.password).toString('base64'));
-        }
-
-        req.on('timeout', () => {
-            // set a retryable error code
-            statusCode = 524;
-            req.destroy(new Error('HTTP request timeout, no response from server in time'));
-        });
-        req.on('error', err => {
-            // if the error is thrown while the request is sent, statusCode is -1 => no retry
-            // request timeout comes through with statusCode 524 => retry
-            // if the error is thrown while the response is processed, the statusCode is taken from the response => retry depends on statusCode
-            if (isRetryable(statusCode) && retryTimeout > 0) {
-                if (retryBegin < 0) {
-                    retryBegin = Date.now();
-                    retryInterval = 10;
-                } else {
-                    const elapsed = Date.now() - retryBegin;
-                    if (elapsed > retryTimeout) {
-                        reject(err);
-                        return;
-                    }
-                }
-                const jitter = Math.floor(Math.random() * 10) - 5;
-                setTimeout(() => {
-                    retryInterval = Math.min(retryInterval * 2, 1000);
-                    sendHttp(sender, request, options, data, retryTimeout, retryBegin, retryInterval)
-                        .then(() => resolve(true))
-                        .catch(e => reject(e));
-                }, retryInterval + jitter);
-            } else {
-                reject(err);
-            }
-        });
-        req.write(data, err => err ? reject(err) : () => {});
-        req.end();
-    });
-}
-
-/*
-We are retrying on the following response codes (copied from the Rust client):
-500:  Internal Server Error
-503:  Service Unavailable
-504:  Gateway Timeout
-
-// Unofficial extensions
-507:  Insufficient Storage
-509:  Bandwidth Limit Exceeded
-523:  Origin is Unreachable
-524:  A Timeout Occurred
-529:  Site is overloaded
-599:  Network Connect Timeout Error
-*/
-function isRetryable(statusCode) {
-    return [500, 503, 504, 507, 509, 523, 524, 529, 599].includes(statusCode);
-}
-
-async function autoFlush(sender) {
-    if (sender.autoFlush && sender.pendingRowCount > 0 && (
-        (sender.autoFlushRows > 0 && sender.pendingRowCount >= sender.autoFlushRows) ||
-        (sender.autoFlushInterval > 0 && Date.now() - sender.lastFlushTime >= sender.autoFlushInterval)
-    )) {
-        await sender.flush();
-    }
-}
-
-function sendTcp(sender, data) {
-    return new Promise((resolve, reject) => {
-        sender.socket.write(data, err => {
-            err ? reject(err) : sender.doResolve(resolve);
-        });
-    });
-}
-
-function checkCapacity(sender, data, base = 0) {
-    let length = base;
-    for (const str of data) {
-        length += Buffer.byteLength(str, 'utf8');
-    }
-    if (sender.position + length > sender.bufferSize) {
-        let newSize = sender.bufferSize;
-        do {
-            newSize += sender.bufferSize;
-        } while(sender.position + length > newSize);
-        sender.resize(newSize);
-    }
-}
-
-function compact(sender) {
-    if (sender.endOfLastRow > 0) {
-        sender.buffer.copy(sender.buffer, 0, sender.endOfLastRow, sender.position);
-        sender.position = sender.position - sender.endOfLastRow;
-        sender.endOfLastRow = 0;
-
-        sender.lastFlushTime = Date.now();
-        sender.pendingRowCount = 0;
-    }
-}
-
-function writeColumn(sender, name, value, writeValue, valueType) {
-    if (typeof name !== 'string') {
-        throw new Error(`Column name must be a string, received ${typeof name}`);
-    }
-    if (valueType != null && typeof value !== valueType) {
-        throw new Error(`Column value must be of type ${valueType}, received ${typeof value}`);
-    }
-    if (!sender.hasTable) {
-        throw new Error('Column can be set only after table name is set');
-    }
-    checkCapacity(sender, [name], 2 + name.length);
-    write(sender, sender.hasColumns ? ',' : ' ');
-    validateColumnName(name, sender.maxNameLength);
-    writeEscaped(sender, name);
-    write(sender, '=');
-    writeValue();
-    sender.hasColumns = true;
-}
-
-function write(sender, data) {
-    sender.position += sender.buffer.write(data, sender.position);
-    if (sender.position > sender.bufferSize) {
-        throw new Error(`Buffer overflow [position=${sender.position}, bufferSize=${sender.bufferSize}]`);
-    }
-}
-
-function writeEscaped(sender, data, quoted = false) {
-    for (const ch of data) {
-        if (ch > '\\') {
-            write(sender, ch);
-            continue;
-        }
-
-        switch (ch) {
-            case ' ':
-            case ',':
-            case '=':
-                if (!quoted) {
-                    write(sender, '\\');
-                }
-                write(sender, ch);
-                break;
-            case '\n':
-            case '\r':
-                write(sender, '\\');
-                write(sender, ch);
-                break;
-            case '"':
-                if (quoted) {
-                    write(sender, '\\');
-                }
-                write(sender, ch);
-                break;
-            case '\\':
-                write(sender, '\\\\');
-                break;
-            default:
-                write(sender, ch);
-                break;
-        }
-    }
-}
-
-function timestampToMicros(timestamp, unit) {
-    switch (unit) {
-        case 'ns':
-            return timestamp / 1000n;
-        case 'us':
-            return timestamp;
-        case 'ms':
-            return timestamp * 1000n;
-        default:
-            throw new Error('Unknown timestamp unit: ' + unit);
-    }
-}
-
-function timestampToNanos(timestamp, unit) {
-    switch (unit) {
-        case 'ns':
-            return timestamp;
-        case 'us':
-            return timestamp * 1000n;
-        case 'ms':
-            return timestamp * 1000_000n;
-        default:
-            throw new Error('Unknown timestamp unit: ' + unit);
-    }
-}
-
-function replaceDeprecatedOptions(options) {
-    // deal with deprecated options
-    if (options.copyBuffer) {
-        options.copy_buffer = options.copyBuffer;
-        options.copyBuffer = undefined;
-    }
-    if (options.bufferSize) {
-        options.init_buf_size = options.bufferSize;
-        options.bufferSize = undefined;
-    }
-}
-
-function constructAuth(options) {
-    if (!options.username && !options.token && !options.password) {
-        // no intention to authenticate
-        return;
-    }
-    if (!options.username || !options.token) {
-        throw new Error('TCP transport requires a username and a private key for authentication, ' +
-            'please, specify the \'username\' and \'token\' config options');
-    }
-
-    options.auth = {
-        keyId: options.username,
-        token: options.token
-    };
-}
-
-function constructJwk(options) {
-    if (options.auth) {
-        if (!options.auth.keyId) {
-            throw new Error('Missing username, please, specify the \'keyId\' property of the \'auth\' config option. ' +
-                'For example: new Sender({protocol: \'tcp\', host: \'host\', auth: {keyId: \'username\', token: \'private key\'}})');
-        }
-        if (typeof options.auth.keyId !== 'string') {
-            throw new Error('Please, specify the \'keyId\' property of the \'auth\' config option as a string. ' +
-                'For example: new Sender({protocol: \'tcp\', host: \'host\', auth: {keyId: \'username\', token: \'private key\'}})');
-        }
-        if (!options.auth.token) {
-            throw new Error('Missing private key, please, specify the \'token\' property of the \'auth\' config option. ' +
-                'For example: new Sender({protocol: \'tcp\', host: \'host\', auth: {keyId: \'username\', token: \'private key\'}})');
-        }
-        if (typeof options.auth.token !== 'string') {
-            throw new Error('Please, specify the \'token\' property of the \'auth\' config option as a string. ' +
-                'For example: new Sender({protocol: \'tcp\', host: \'host\', auth: {keyId: \'username\', token: \'private key\'}})');
-        }
-
-        return {
-            kid: options.auth.keyId,
-            d: options.auth.token,
-            ...PUBLIC_KEY,
-            kty: 'EC',
-            crv: 'P-256'
-        };
-    } else {
-        return options.jwk;
-    }
-}
-
-exports.Sender = Sender;
-exports.DEFAULT_BUFFER_SIZE = DEFAULT_BUFFER_SIZE;
-exports.DEFAULT_MAX_BUFFER_SIZE = DEFAULT_MAX_BUFFER_SIZE;
-
-
-
-
- - - -
- -
- Documentation generated by - JSDoc 4.0.2 on Tue Aug 13 - 2024 14:27:30 GMT+0300 (Eastern European Summer Time) -
- - - - - diff --git a/docs/src_options.js.html b/docs/src_options.js.html deleted file mode 100644 index 0038d94..0000000 --- a/docs/src_options.js.html +++ /dev/null @@ -1,453 +0,0 @@ - - - - - JSDoc: Source: src/options.js - - - - - - - - - -
-

Source: src/options.js

- -
-
-
'use strict';
-
-const HTTP_PORT = 9000;
-const TCP_PORT = 9009;
-
-const HTTP = 'http';
-const HTTPS = 'https';
-const TCP = 'tcp';
-const TCPS = 'tcps';
-
-const ON = 'on';
-const OFF = 'off';
-const UNSAFE_OFF = 'unsafe_off';
-
-/** @classdesc
- * Sender configuration options. <br>
- * <br>
- * Properties of the object are initialized through a configuration string. <br>
- * The configuration string has the following format: <i>&ltprotocol&gt::&ltkey&gt=&ltvalue&gt;&ltkey&gt=&ltvalue&gt;...;</i> <br>
- * The keys are case-sensitive, the trailing semicolon is optional. <br>
- * The values are validated, and an error is thrown if the format is invalid. <br>
- * <br>
- * Connection and protocol options
- * <ul>
- * <li> <b>protocol</b>: <i>enum, accepted values: http, https, tcp, tcps</i> - The protocol used to communicate with the server. <br>
- * When <i>https</i> or <i>tcps</i> used, the connection is secured with TLS encryption.
- * </li>
- * <li> addr: <i>string</i> - Hostname and port, separated by colon. This key is mandatory, but the port part is optional. <br>
- * If no port is specified, a default will be used. <br>
- * When the protocol is HTTP/HTTPS, the port defaults to 9000. When the protocol is TCP/TCPS, the port defaults to 9009. <br>
- * Examples: <i>http::addr=localhost:9000</i>, <i>https::addr=localhost:9000</i>, <i>http::addr=localhost</i>, <i>tcp::addr=localhost:9009</i>
- * </li>
- * </ul>
- * <br>
- * Authentication options
- * <ul>
- * <li> username: <i>string</i> - Used for authentication. <br>
- * In case of HTTP Basic authentication should be accompanied by the <i>password</i> option. <br>
- * If the TCP transport used with JWK token authentication, then should be accompanied by the <i>token</i> option.
- * </li>
- * <li> password: <i>string</i> - Password for HTTP Basic authentication, should be accompanied by the <i>username</i> option.
- * </li>
- * <li> token: <i>string</i> - In case of HTTP Bearer token authentication it contains the bearer token. <br>
- * If the TCP transport used with JWK token authentication, then it contains the private key part of the JWK token,
- * and it should be accompanied by the <i>username</i> option.
- * </li>
- * </ul>
- * <br>
- * TLS options
- * <ul>
- * <li> tls_verify: <i>enum, accepted values: on, unsafe_off</i> - When the HTTPS or TCPS protocols are selected, TLS encryption is used. <br>
- * The Sender verifies the server's certificate, this check can be disabled by setting this option to <i>off</i>. Can be useful in
- * non-production environments where self-signed certificates might be used, but generally not recommended to use.
- * </li>
- * <li> tls_ca: <i>string</i> - Path to a file containing the root CA's certificate in PEM format. <br>
- * Can be useful when self-signed certificates are used, otherwise should not be set.
- * </li>
- * </ul>
- * <br>
- * Auto flush options
- * <ul>
- * <li> auto_flush: <i>enum, accepted values: on, off</i> - The Sender automatically flushes the buffer by default, this can be switched off
- * by setting this option to <i>off</i>. <br>
- * When disabled, the flush() method of the Sender has to be called explicitly to make sure data is sent to the server.
- * </li>
- * <li> auto_flush_rows: <i>integer</i> - The number of rows that will trigger a flush. When set to 0, row-based flushing is disabled. <br>
- * The Sender will default this parameter to 75000 rows when HTTP protocol is used, and to 600 in case of TCP protocol.
- * </li>
- * <li> auto_flush_interval: <i>integer</i> - The number of milliseconds that will trigger a flush, default value is 1000.
- * When set to 0, interval-based flushing is disabled. <br>
- * Note that the setting is checked only when a new row is added to the buffer. There is no timer registered to flush the buffer automatically.
- * </li>
- * </ul>
- * <br>
- * Buffer sizing options
- * <ul>
- * <li> init_buf_size: <i>integer</i> - Initial buffer size, defaults to 64 KiB in the Sender.
- * </li>
- * <li> max_buf_size: <i>integer</i> - Maximum buffer size, defaults to 100 MiB in the Sender. <br>
- * If the buffer would need to be extended beyond the maximum size, an error is thrown.
- * </li>
- * </ul>
- * <br>
- * HTTP request specific options
- * <ul>
- * <li> request_timeout: <i>integer</i> - The time in milliseconds to wait for a response from the server, set to 10 seconds by default. <br>
- * This is in addition to the calculation derived from the <i>request_min_throughput</i> parameter.
- * </li>
- * <li> request_min_throughput: <i>integer</i> - Minimum expected throughput in bytes per second for HTTP requests, set to 100 KiB/s seconds by default. <br>
- * If the throughput is lower than this value, the connection will time out. This is used to calculate an additional
- * timeout on top of <i>request_timeout</i>. This is useful for large requests. You can set this value to 0 to disable this logic.
- * </li>
- * <li> retry_timeout: <i>integer</i> - The time in milliseconds to continue retrying after a failed HTTP request, set to 10 seconds by default. <br>
- * The interval between retries is an exponential backoff starting at 10ms and doubling after each failed attempt up to a maximum of 1 second.
- * </li>
- * </ul>
- * <br>
- * Other options
- * <ul>
- * <li> max_name_len: <i>integer</i> - The maximum length of a table or column name, the Sender defaults this parameter to 127. <br>
- * Recommended to use the same setting as the server, which also uses 127 by default.
- * </li>
- * <li> copy_buffer: <i>enum, accepted values: on, off</i> - By default the Sender creates a new buffer for every flush() call,
- * and the data to be sent to the server is copied into this new buffer.
- * Setting the flag to <i>off</i> results in reusing the same buffer instance for each flush() call. <br>
- * Use this flag only if calls to the client are serialised.
- * </li>
- * </ul>
- */
-class SenderOptions {
-
-    protocol;
-    addr;
-    host; // derived from addr
-    port; // derived from addr
-
-    // replaces `auth` and `jwk` options
-    username;
-    password;
-    token;
-    token_x; // allowed, but ignored
-    token_y; // allowed, but ignored
-
-    auto_flush;
-    auto_flush_rows;
-    auto_flush_interval;
-
-    // replaces `copyBuffer` option
-    copy_buffer;
-
-    request_min_throughput;
-    request_timeout;
-    retry_timeout;
-
-    // replaces `bufferSize` option
-    init_buf_size;
-    max_buf_size;
-
-    tls_verify;
-    tls_ca;
-    tls_roots;          // not supported
-    tls_roots_password; // not supported
-
-    max_name_len;
-
-    log;
-
-    /**
-     * Creates a Sender options object by parsing the provided configuration string.
-     *
-     * @param {string} configurationString - Configuration string. <br>
-     * @param {function} log - Optional logging function used by the Sender. <br>
-     * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void<i>.
-     */
-    constructor(configurationString, log = undefined) {
-        parseConfigurationString(configurationString);
-
-        if (log && typeof log !== 'function') {
-            throw new Error('Invalid logging function');
-        }
-        this.log = log;
-    }
-
-    /**
-     * Creates a Sender options object by parsing the provided configuration string.
-     *
-     * @param {string} configurationString - Configuration string. <br>
-     * @param {function} log - Optional logging function used by the Sender. <br>
-     * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void<i>. <br>
-     *
-     * @return {SenderOptions} An instance of the Sender configuration object initialized from the provided configuration string.
-     */
-    static fromConfig(configurationString, log = undefined) {
-        return new SenderOptions(configurationString, log);
-    }
-
-    /**
-     * Creates a Sender options object by parsing the configuration string set in the QDB_CLIENT_CONF environment variable.
-     *
-     * @param {function} log - Optional logging function used by the Sender. <br>
-     * Prototype: <i>(level: 'error'|'warn'|'info'|'debug', message: string) => void<i>. <br>
-     *
-     * @return {SenderOptions} An instance of the Sender configuration object initialized from the QDB_CLIENT_CONF environment variable.
-     */
-    static fromEnv(log = undefined) {
-        return SenderOptions.fromConfig(process.env.QDB_CLIENT_CONF, log);
-    }
-}
-
-function parseConfigurationString(options, configString) {
-    if (!configString) {
-        throw new Error('Configuration string is missing or empty');
-    }
-
-    const position = parseProtocol(options, configString);
-    parseSettings(options, configString, position);
-    parseAddress(options);
-    parseBufferSizes(options);
-    parseAutoFlushOptions(options);
-    parseTlsOptions(options);
-    parseRequestTimeoutOptions(options);
-    parseMaxNameLength(options);
-    parseCopyBuffer(options);
-}
-
-function parseSettings(options, configString, position) {
-    let index = configString.indexOf(';', position);
-    while (index > -1) {
-        if (index + 1 < configString.length && configString.charAt(index + 1) === ';') {
-            index = configString.indexOf(';', index + 2);
-            continue;
-        }
-
-        parseSetting(options, configString, position, index);
-
-        position = index + 1;
-        index = configString.indexOf(';', position);
-    }
-    if (position < configString.length) {
-        parseSetting(options, configString, position, configString.length);
-    }
-}
-
-function parseSetting(options, configString, position, index) {
-    const setting = configString.slice(position, index).replaceAll(';;', ';');
-    const equalsIndex = setting.indexOf('=');
-    if (equalsIndex < 0) {
-        throw new Error(`Missing \'=\' sign in \'${setting}\'`);
-    }
-    const key = setting.slice(0, equalsIndex);
-    const value = setting.slice(equalsIndex + 1);
-    validateConfigKey(key);
-    validateConfigValue(key, value);
-    options[key] = value;
-}
-
-const ValidConfigKeys = [
-    'addr',
-    'username', 'password', 'token', 'token_x', 'token_y',
-    'auto_flush', 'auto_flush_rows', 'auto_flush_interval',
-    'copy_buffer',
-    'request_min_throughput', 'request_timeout', 'retry_timeout',
-    'init_buf_size', 'max_buf_size',
-    'max_name_len',
-    'tls_verify', 'tls_ca', 'tls_roots', 'tls_roots_password'
-];
-
-function validateConfigKey(key) {
-    if (!ValidConfigKeys.includes(key)) {
-        throw new Error(`Unknown configuration key: \'${key}\'`);
-    }
-}
-
-function validateConfigValue(key, value) {
-    if (!value) {
-        throw new Error(`Invalid configuration, value is not set for \'${key}\'`);
-    }
-    for (let i = 0; i < value.length; i++) {
-        const unicode = value.codePointAt(i);
-        if (unicode < 0x20 || (unicode > 0x7E && unicode < 0xA0)) {
-            throw new Error(`Invalid configuration, control characters are not allowed: \'${value}\'`);
-        }
-    }
-}
-
-function parseProtocol(options, configString) {
-    let index = configString.indexOf('::');
-    if (index < 0) {
-        throw new Error('Missing protocol, configuration string format: \'protocol::key1=value1;key2=value2;key3=value3;\'');
-    }
-
-    options.protocol = configString.slice(0, index);
-    switch (options.protocol) {
-        case HTTP:
-        case HTTPS:
-        case TCP:
-        case TCPS:
-            break;
-        default:
-            throw new Error(`Invalid protocol: \'${options.protocol}\', accepted protocols: \'http\', \'https\', \'tcp\', \'tcps\'`);
-    }
-    return index + 2;
-}
-
-function parseAddress(options) {
-    if (!options.addr) {
-        throw new Error('Invalid configuration, \'addr\' is required');
-    }
-
-    const index = options.addr.indexOf(':');
-    if (index < 0) {
-        options.host = options.addr;
-        switch (options.protocol) {
-            case HTTP:
-            case HTTPS:
-                options.port = HTTP_PORT;
-                return;
-            case TCP:
-            case TCPS:
-                options.port = TCP_PORT;
-                return;
-            default:
-                throw new Error(`Invalid protocol: \'${options.protocol}\', accepted protocols: \'http\', \'https\', \'tcp\', \'tcps\'`);
-        }
-    }
-
-    options.host = options.addr.slice(0, index);
-    if (!options.host) {
-        throw new Error(`Host name is required`);
-    }
-
-    const portStr = options.addr.slice(index + 1);
-    if (!portStr) {
-        throw new Error(`Port is required`);
-    }
-    options.port = Number(portStr);
-    if (isNaN(options.port)) {
-        throw new Error(`Invalid port: \'${portStr}\'`);
-    }
-    if (!Number.isInteger(options.port) || options.port < 1) {
-        throw new Error(`Invalid port: ${options.port}`);
-    }
-}
-
-function parseBufferSizes(options) {
-    parseInteger(options, 'init_buf_size', 'initial buffer size', 1);
-    parseInteger(options, 'max_buf_size', 'max buffer size', 1);
-}
-
-function parseAutoFlushOptions(options) {
-    parseBoolean(options, 'auto_flush', 'auto flush');
-    parseInteger(options, 'auto_flush_rows', 'auto flush rows', 0);
-    parseInteger(options, 'auto_flush_interval', 'auto flush interval', 0);
-}
-
-function parseTlsOptions(options) {
-    parseBoolean(options, 'tls_verify', 'TLS verify', UNSAFE_OFF);
-
-    if (options.tls_roots || options.tls_roots_password) {
-        throw new Error('\'tls_roots\' and \'tls_roots_password\' options are not supported, please, ' +
-            'use the \'tls_ca\' option or the NODE_EXTRA_CA_CERTS environment variable instead');
-    }
-}
-
-function parseRequestTimeoutOptions(options) {
-    parseInteger(options, 'request_min_throughput', 'request min throughput', 1);
-    parseInteger(options, 'request_timeout', 'request timeout', 1);
-    parseInteger(options, 'retry_timeout', 'retry timeout', 0);
-}
-
-function parseMaxNameLength(options) {
-    parseInteger(options, 'max_name_len', 'max name length', 1);
-}
-
-function parseCopyBuffer(options) {
-    parseBoolean(options, 'copy_buffer', 'copy buffer');
-}
-
-function parseBoolean(options, property, description, offValue = OFF) {
-    if (options[property]) {
-        const property_str = options[property];
-        switch (property_str) {
-            case ON:
-                options[property] = true;
-                break;
-            case offValue:
-                options[property] = false;
-                break;
-            default:
-                throw new Error(`Invalid ${description} option: \'${property_str}\'`);
-        }
-    }
-}
-
-function parseInteger(options, property, description, lowerBound) {
-    if (options[property]) {
-        const property_str = options[property];
-        options[property] = Number(property_str);
-        if (isNaN(options[property])) {
-            throw new Error(`Invalid ${description} option, not a number: \'${property_str}\'`);
-        }
-        if (!Number.isInteger(options[property]) || options[property] < lowerBound) {
-            throw new Error(`Invalid ${description} option: ${options[property]}`);
-        }
-    }
-}
-
-exports.SenderOptions = SenderOptions;
-exports.HTTP = HTTP;
-exports.HTTPS = HTTPS;
-exports.TCP = TCP;
-exports.TCPS = TCPS;
-
-
-
-
- - - -
- -
- Documentation generated by - JSDoc 4.0.2 on Wed Apr 17 - 2024 03:38:42 GMT+0100 (British Summer Time) -
- - - - - diff --git a/docs/src_sender.js.html b/docs/src_sender.js.html deleted file mode 100644 index e822b39..0000000 --- a/docs/src_sender.js.html +++ /dev/null @@ -1,934 +0,0 @@ - - - - - JSDoc: Source: src/sender.js - - - - - - - - - -
-

Source: src/sender.js

- -
-
-
'use strict';
-
-/* eslint-disable no-unused-vars */
-
-const { readFileSync } = require("fs");
-const { Buffer } = require('buffer');
-const { log } = require('./logging');
-const { validateTableName, validateColumnName } = require('./validation');
-const { SenderOptions, HTTP, HTTPS, TCP, TCPS } = require('./options');
-const http = require('http');
-const https = require('https');
-const net = require('net');
-const tls = require('tls');
-const crypto = require('crypto');
-
-const HTTP_NO_CONTENT = 204;
-
-const DEFAULT_HTTP_AUTO_FLUSH_ROWS = 75000;
-const DEFAULT_TCP_AUTO_FLUSH_ROWS = 600;
-const DEFAULT_AUTO_FLUSH_INTERVAL = 1000; // 1 sec
-
-const DEFAULT_MAX_NAME_LENGTH = 127;
-
-const DEFAULT_REQUEST_MIN_THROUGHPUT = 102400; // 100 KB/sec
-const DEFAULT_REQUEST_TIMEOUT = 10000; // 10 sec
-const DEFAULT_RETRY_TIMEOUT = 10000; // 10 sec
-
-const DEFAULT_BUFFER_SIZE = 65536; //  64 KB
-const DEFAULT_MAX_BUFFER_SIZE = 104857600; // 100 MB
-
-// an arbitrary public key, not used in authentication
-// only used to construct a valid JWK token which is accepted by the crypto API
-const PUBLIC_KEY = {
-    x: 'aultdA0PjhD_cWViqKKyL5chm6H1n-BiZBo_48T-uqc',
-    y: '__ptaol41JWSpTTL525yVEfzmY8A6Vi_QrW1FjKcHMg'
-};
-
-/** @classdesc
- * The QuestDB client's API provides methods to connect to the database, ingest data, and close the connection.
- * The supported protocols are HTTP and TCP. HTTP is preferred because it provides feedback in the HTTP response. <br>
- * Based on our benchmarks HTTP also provides higher throughput if configured to ingest data in bigger batches.
- * <p>
- * The client supports authentication. <br>
- * Authentication details can be passed to the Sender in its configuration options. <br>
- * The client support Basic username/password and Bearer token authentication methods when used with HTTP protocol,
- * and JWK token (user id and the user's private key) authentication when ingesting data via TCP. <br>
- * Please, note that authentication is enabled by default in QuestDB Enterprise only. <br>
- * Details on how to configure authentication in the open source version of QuestDB: {@link https://questdb.io/docs/reference/api/ilp/authenticate}
- * </p>
- * <p>
- * The client also supports TLS encryption for both, HTTP and TCP transports to provide a secure connection. <br>
- * Please, note that the open source version of QuestDB does not support TLS, and requires an external reverse-proxy, such as Nginx to enable encryption.
- * </p>
- * <p>
- * More details on configuration options can be found in the description of SenderOptions.
- * </p>
- */
-class Sender {
-
-    http;       // true if the protocol is HTTP/HTTPS, false if it is TCP/TCPS
-    secure;     // true if the protocol is HTTPS or TCPS, false otherwise
-    host;
-    port;
-
-    socket;
-
-    username;
-    password;
-    token;
-
-    tlsVerify;
-    tlsCA;
-
-    bufferSize;
-    maxBufferSize;
-    buffer;
-    toBuffer;
-    doResolve;
-    position;
-    endOfLastRow;
-
-    autoFlush;
-    autoFlushRows;
-    autoFlushInterval;
-    lastFlushTime;
-    pendingRowCount;
-
-    requestMinThroughput;
-    requestTimeout;
-    retryTimeout;
-
-    hasTable;
-    hasSymbols;
-    hasColumns;
-
-    maxNameLength;
-
-    log;
-
-    /**
-     * Creates an instance of Sender.
-     *
-     * @param {SenderOptions} options - Sender configuration object. <br>
-     * See SenderOptions documentation for detailed description of configuration options. <br>
-     */
-    constructor(options = undefined) {
-        options = initSenderOptions(options);
-
-        this.log = typeof options.log === 'function' ? options.log : log;
-
-        switch (options.protocol) {
-            case HTTP:
-                this.http = true;
-                this.secure = false;
-                break;
-            case HTTPS:
-                this.http = true;
-                this.secure = true;
-                break;
-            case TCP:
-                this.http = false;
-                this.secure = false;
-                break;
-            case TCPS:
-                this.http = false;
-                this.secure = true;
-                break;
-            default:
-                throw new Error(`Invalid protocol: \'${options.protocol}\'`);
-        }
-
-        this.host = options.host;
-        this.port = options.port;
-
-        if (this.http) {
-            this.username = options.username;
-            this.password = options.password;
-            this.token = options.token;
-        } else {
-            if (!options.auth && !options.jwk) {
-                constructAuth(options);
-            }
-            this.jwk = constructJwk(options);
-        }
-
-        this.tlsVerify = isBoolean(options.tls_verify) ? options.tls_verify : true;
-        this.tlsCA = options.tls_ca ? readFileSync(options.tls_ca) : undefined;
-
-        this.autoFlush = isBoolean(options.auto_flush) ? options.auto_flush : true;
-        this.autoFlushRows = isInteger(options.auto_flush_rows, 0) ? options.auto_flush_rows : (this.http ? DEFAULT_HTTP_AUTO_FLUSH_ROWS : DEFAULT_TCP_AUTO_FLUSH_ROWS);
-        this.autoFlushInterval = isInteger(options.auto_flush_interval, 0) ? options.auto_flush_interval : DEFAULT_AUTO_FLUSH_INTERVAL;
-
-        this.maxNameLength = isInteger(options.max_name_len, 1) ? options.max_name_len : DEFAULT_MAX_NAME_LENGTH;
-
-        this.requestMinThroughput = isInteger(options.request_min_throughput, 1) ? options.request_min_throughput : DEFAULT_REQUEST_MIN_THROUGHPUT;
-        this.requestTimeout = isInteger(options.request_timeout, 1) ? options.request_timeout : DEFAULT_REQUEST_TIMEOUT;
-        this.retryTimeout = isInteger(options.retry_timeout, 0) ? options.retry_timeout : DEFAULT_RETRY_TIMEOUT;
-
-        const noCopy = isBoolean(options.copy_buffer) && !options.copy_buffer;
-        this.toBuffer = noCopy ? this.toBufferView : this.toBufferNew;
-        this.doResolve = noCopy
-            ? (resolve) => {
-                compact(this);
-                resolve(true);
-            }
-            : (resolve) => {
-                resolve(true);
-            }
-        this.maxBufferSize = isInteger(options.max_buf_size, 1) ? options.max_buf_size : DEFAULT_MAX_BUFFER_SIZE;
-        this.resize(isInteger(options.init_buf_size, 1) ? options.init_buf_size : DEFAULT_BUFFER_SIZE);
-        this.reset();
-    }
-
-    static fromConfig(configurationString) {
-        return new Sender(SenderOptions.fromConfig(configurationString));
-    }
-
-    static fromEnv() {
-        return new Sender(SenderOptions.fromConfig(process.env.QDB_CLIENT_CONF));
-    }
-
-    /**
-     * Extends the size of the sender's buffer. <br>
-     * Can be used to increase the size of buffer if overflown.
-     * The buffer's content is copied into the new buffer.
-     *
-     * @param {number} bufferSize - New size of the buffer used by the sender, provided in bytes.
-     */
-    resize(bufferSize) {
-        if (bufferSize > this.maxBufferSize) {
-            throw new Error(`Max buffer size is ${this.maxBufferSize} bytes, requested buffer size: ${bufferSize}`);
-        }
-        this.bufferSize = bufferSize;
-        const newBuffer = Buffer.alloc(this.bufferSize + 1, 0, 'utf8');
-        if (this.buffer) {
-            this.buffer.copy(newBuffer);
-        }
-        this.buffer = newBuffer;
-    }
-
-    /**
-     * Resets the buffer, data added to the buffer will be lost. <br>
-     * In other words it clears the buffer and sets the writing position to the beginning of the buffer.
-     *
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    reset() {
-        this.position = 0;
-        this.lastFlushTime = Date.now();
-        this.pendingRowCount = 0;
-        startNewRow(this);
-        return this;
-    }
-
-    /**
-     * Creates a TCP connection to the database.
-     *
-     * @param {net.NetConnectOpts | tls.ConnectionOptions} connectOptions - Connection options, host and port are required.
-     * @param {boolean} [secure = false] - If true connection will use TLS encryption.
-     *
-     * @return {Promise<boolean>} Resolves to true if client is connected.
-     */
-    connect(connectOptions = undefined, secure = false) {
-        if (this.http) {
-            throw new Error('\'connect()\' should be called only if the sender connects via TCP');
-        }
-
-        if (secure) {
-            this.secure = secure;
-        }
-
-        if (!connectOptions) {
-            connectOptions = {
-                host: this.host,
-                port: this.port,
-                ca: this.tlsCA
-            }
-        }
-        if (!connectOptions.host) {
-            throw new Error('Hostname is not set');
-        }
-        if (!connectOptions.port) {
-            throw new Error('Port is not set');
-        }
-
-        let self = this;
-
-        return new Promise((resolve, reject) => {
-            let authenticated = false;
-            let data;
-
-            if (this.socket) {
-                throw new Error('Sender connected already');
-            }
-            this.socket = !this.secure
-                ? net.connect(connectOptions)
-                : tls.connect(connectOptions, async () => {
-                    await checkServerCert(self, reject);
-                });
-            this.socket.setKeepAlive(true);
-
-            this.socket.on('data', async raw => {
-                data = !data ? raw : Buffer.concat([data, raw]);
-                if (!authenticated) {
-                    authenticated = await authenticate(self, data);
-                    if (authenticated) {
-                        resolve(true);
-                    }
-                } else {
-                    this.log('warn', `Received unexpected data: ${data}`);
-                }
-            })
-            .on('ready', async () => {
-                this.log('info', `Successfully connected to ${connectOptions.host}:${connectOptions.port}`);
-                if (self.jwk) {
-                    this.log('info', `Authenticating with ${connectOptions.host}:${connectOptions.port}`);
-                    await self.socket.write(`${self.jwk.kid}\n`, err => {
-                        if (err) {
-                            reject(err);
-                        }
-                    });
-                } else {
-                    authenticated = true;
-                    resolve(true);
-                }
-            })
-            .on('error', err => {
-                this.log('error', err);
-                reject(err);
-            });
-        });
-    }
-
-    /**
-     * Closes the TCP connection to the database. <br>
-     * Data sitting in the Sender's buffer will be lost unless flush() is called before close().
-     */
-    async close() {
-        if (this.socket) {
-            const address = this.socket.remoteAddress;
-            const port = this.socket.remotePort;
-            this.socket.destroy();
-            this.log('info', `Connection to ${address}:${port} is closed`);
-        }
-    }
-
-    /**
-     * Sends the buffer's content to the database and compacts the buffer.
-     * If the last row is not finished it stays in the sender's buffer.
-     *
-     * @return {Promise<boolean>} Resolves to true when there was data in the buffer to send.
-     */
-    async flush() {
-        const data = this.toBuffer(this.endOfLastRow);
-        if (!data) {
-            return false;
-        }
-
-        if (this.http) {
-            const request = this.secure ? https.request : http.request;
-            const options = createRequestOptions(this, data);
-            return sendHttp(this, request, options, data, this.retryTimeout);
-        } else {
-            if (!this.socket) {
-                throw new Error('Sender is not connected');
-            }
-            return sendTcp(this, data);
-        }
-    }
-
-    /**
-     * @ignore
-     * @return {Buffer} Returns a cropped buffer ready to send to the server or null if there is nothing to send.
-     * The returned buffer is backed by the sender's buffer.
-     */
-    toBufferView(pos = this.position) {
-        return pos > 0
-            ? this.buffer.subarray(0, pos)
-            : null;
-    }
-
-    /**
-     * @ignore
-     * @return {Buffer} Returns a cropped buffer ready to send to the server or null if there is nothing to send.
-     * The returned buffer is a copy of the sender's buffer.
-     */
-    toBufferNew(pos = this.position) {
-        if (pos > 0) {
-            const data = Buffer.allocUnsafe(pos);
-            this.buffer.copy(data, 0, 0, pos);
-            compact(this);
-            return data;
-        }
-        return null;
-    }
-
-    /**
-     * Write the table name into the buffer of the sender.
-     *
-     * @param {string} table - Table name.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    table(table) {
-        if (typeof table !== 'string') {
-            throw new Error(`Table name must be a string, received ${typeof table}`);
-        }
-        if (this.hasTable) {
-            throw new Error('Table name has already been set');
-        }
-        validateTableName(table, this.maxNameLength);
-        checkCapacity(this, [table]);
-        writeEscaped(this, table);
-        this.hasTable = true;
-        return this;
-    }
-
-    /**
-     * Write a symbol name and value into the buffer of the sender.
-     *
-     * @param {string} name - Symbol name.
-     * @param {any} value - Symbol value, toString() will be called to extract the actual symbol value from the parameter.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    symbol(name, value) {
-        if (typeof name !== 'string') {
-            throw new Error(`Symbol name must be a string, received ${typeof name}`);
-        }
-        if (!this.hasTable || this.hasColumns) {
-            throw new Error('Symbol can be added only after table name is set and before any column added');
-        }
-        const valueStr = value.toString();
-        checkCapacity(this, [name, valueStr], 2 + name.length + valueStr.length);
-        write(this, ',');
-        validateColumnName(name, this.maxNameLength);
-        writeEscaped(this, name);
-        write(this, '=');
-        writeEscaped(this, valueStr);
-        this.hasSymbols = true;
-        return this;
-    }
-
-    /**
-     * Write a string column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {string} value - Column value, accepts only string values.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    stringColumn(name, value) {
-        writeColumn(this, name, value, () => {
-            checkCapacity(this, [value], 2 + value.length);
-            write(this, '"');
-            writeEscaped(this, value, true);
-            write(this, '"');
-        }, 'string');
-        return this;
-    }
-
-    /**
-     * Write a boolean column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {boolean} value - Column value, accepts only boolean values.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    booleanColumn(name, value) {
-        writeColumn(this, name, value, () => {
-            checkCapacity(this, [], 1);
-            write(this, value ? 't' : 'f');
-        }, 'boolean');
-        return this;
-    }
-
-    /**
-     * Write a float column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {number} value - Column value, accepts only number values.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    floatColumn(name, value) {
-        writeColumn(this, name, value, () => {
-            const valueStr = value.toString();
-            checkCapacity(this, [valueStr], valueStr.length);
-            write(this, valueStr);
-        }, 'number');
-        return this;
-    }
-
-    /**
-     * Write an integer column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {number} value - Column value, accepts only number values.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    intColumn(name, value) {
-        if (!Number.isInteger(value)) {
-            throw new Error(`Value must be an integer, received ${value}`);
-        }
-        writeColumn(this, name, value, () => {
-            const valueStr = value.toString();
-            checkCapacity(this, [valueStr], 1 + valueStr.length);
-            write(this, valueStr);
-            write(this, 'i');
-        });
-        return this;
-    }
-
-    /**
-     * Write a timestamp column with its value into the buffer of the sender.
-     *
-     * @param {string} name - Column name.
-     * @param {number | bigint} value - Epoch timestamp, accepts numbers or BigInts.
-     * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
-     * @return {Sender} Returns with a reference to this sender.
-     */
-    timestampColumn(name, value, unit = 'us') {
-        if (typeof value !== 'bigint' && !Number.isInteger(value)) {
-            throw new Error(`Value must be an integer or BigInt, received ${value}`);
-        }
-        writeColumn(this, name, value, () => {
-            const valueMicros = timestampToMicros(BigInt(value), unit);
-            const valueStr = valueMicros.toString();
-            checkCapacity(this, [valueStr], 1 + valueStr.length);
-            write(this, valueStr);
-            write(this, 't');
-        });
-        return this;
-    }
-
-    /**
-     * Closing the row after writing the designated timestamp into the buffer of the sender.
-     *
-     * @param {number | bigint} timestamp - Designated epoch timestamp, accepts numbers or BigInts.
-     * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'.
-     */
-    async at(timestamp, unit = 'us') {
-        if (!this.hasSymbols && !this.hasColumns) {
-            throw new Error('The row must have a symbol or column set before it is closed');
-        }
-        if (typeof timestamp !== 'bigint' && !Number.isInteger(timestamp)) {
-            throw new Error(`Designated timestamp must be an integer or BigInt, received ${timestamp}`);
-        }
-        const timestampNanos = timestampToNanos(BigInt(timestamp), unit);
-        const timestampStr = timestampNanos.toString();
-        checkCapacity(this, [], 2 + timestampStr.length);
-        write(this, ' ');
-        write(this, timestampStr);
-        write(this, '\n');
-        this.pendingRowCount++;
-        startNewRow(this);
-        await autoFlush(this);
-    }
-
-    /**
-     * Closing the row without writing designated timestamp into the buffer of the sender. <br>
-     * Designated timestamp will be populated by the server on this record.
-     */
-    async atNow() {
-        if (!this.hasSymbols && !this.hasColumns) {
-            throw new Error('The row must have a symbol or column set before it is closed');
-        }
-        checkCapacity(this, [], 1);
-        write(this, '\n');
-        this.pendingRowCount++;
-        startNewRow(this);
-        await autoFlush(this);
-    }
-}
-
-function isBoolean(value) {
-    return typeof value === 'boolean';
-}
-
-function isInteger(value, lowerBound) {
-    return typeof value === 'number' && Number.isInteger(value) && value >= lowerBound;
-}
-
-async function checkServerCert(sender, reject) {
-    if (sender.secure && sender.tlsVerify && !sender.socket.authorized) {
-        reject(new Error('Problem with server\'s certificate'));
-        await sender.close();
-    }
-}
-
-async function authenticate(sender, challenge) {
-    // Check for trailing \n which ends the challenge
-    if (challenge.slice(-1).readInt8() === 10) {
-        const keyObject = await crypto.createPrivateKey(
-            {'key': sender.jwk, 'format': 'jwk'}
-        );
-        const signature = await crypto.sign(
-            'RSA-SHA256',
-            challenge.slice(0, challenge.length - 1),
-            keyObject
-        );
-
-        return new Promise((resolve, reject) => {
-            sender.socket.write(`${Buffer.from(signature).toString('base64')}\n`, err => {
-                err ? reject(err) : resolve(true);
-            });
-        });
-    }
-    return false;
-}
-
-function startNewRow(sender) {
-    sender.endOfLastRow = sender.position;
-    sender.hasTable = false;
-    sender.hasSymbols = false;
-    sender.hasColumns = false;
-}
-
-function createRequestOptions(sender, data) {
-    const timeoutMillis = (data.length / sender.requestMinThroughput) * 1000 + sender.requestTimeout;
-    const options = {
-        hostname: sender.host,
-        port: sender.port,
-        path: '/write?precision=n',
-        method: 'POST',
-        timeout: timeoutMillis
-    };
-    if (sender.secure) {
-        options.rejectUnauthorized = sender.tlsVerify;
-        options.ca = sender.tlsCA;
-    }
-    return options;
-}
-
-function sendHttp(sender, request, options, data, retryTimeout, retryBegin = -1, retryInterval = -1) {
-    return new Promise(async (resolve, reject) => {
-        const req = request(options, async response => {
-            const body = [];
-            response
-                .on('data', chunk => {
-                    body.push(chunk);
-                })
-                .on('error', err => {
-                    console.error("resp err=" + err);
-                });
-
-            if (response.statusCode === HTTP_NO_CONTENT) {
-                response.on('end', () => {
-                    if (body.length > 0) {
-                        sender.log('warn', `Unexpected message from server: ${Buffer.concat(body)}`);
-                    }
-                    sender.doResolve(resolve);
-                });
-            } else {
-                if (isRetryable(response.statusCode) && retryTimeout > 0) {
-                    if (retryBegin < 0) {
-                        retryBegin = Date.now();
-                        retryInterval = 10;
-                    } else {
-                        const elapsed = Date.now() - retryBegin;
-                        if (elapsed > retryTimeout) {
-                            reject(new Error(`HTTP request failed, statusCode=${response.statusCode}, error=${Buffer.concat(body)}`));
-                            return;
-                        }
-                    }
-                    const jitter = Math.floor(Math.random() * 10) - 5;
-                    await sleep(retryInterval + jitter);
-                    retryInterval = Math.min(retryInterval * 2, 1000);
-                    try {
-                        await sendHttp(sender, request, options, data, retryTimeout, retryBegin, retryInterval);
-                        resolve(true);
-                    } catch (e) {
-                        reject(e);
-                    }
-                } else {
-                    reject(new Error(`HTTP request failed, statusCode=${response.statusCode}, error=${Buffer.concat(body)}`));
-                }
-            }
-        });
-
-        if (sender.token) {
-            req.setHeader('Authorization', 'Bearer ' + sender.token);
-        } else if (sender.username && sender.password) {
-            req.setHeader('Authorization', 'Basic ' + Buffer.from(sender.username + ':' + sender.password).toString('base64'));
-        }
-        req.on('timeout', () => req.destroy(new Error('HTTP request timeout')));
-        req.on('error', err => reject(err));
-        req.write(data, err => err ? reject(err) : () => {});
-        req.end();
-    });
-}
-
-/*
-We are retrying on the following response codes (copied from the Rust client):
-500:  Internal Server Error
-503:  Service Unavailable
-504:  Gateway Timeout
-
-// Unofficial extensions
-507:  Insufficient Storage
-509:  Bandwidth Limit Exceeded
-523:  Origin is Unreachable
-524:  A Timeout Occurred
-529:  Site is overloaded
-599:  Network Connect Timeout Error
-*/
-function isRetryable(statusCode) {
-    return [500, 503, 504, 507, 509, 523, 524, 529, 599].includes(statusCode);
-}
-
-async function autoFlush(sender) {
-    if (sender.autoFlush && sender.pendingRowCount > 0 && (
-        (sender.autoFlushRows > 0 && sender.pendingRowCount >= sender.autoFlushRows) ||
-        (sender.autoFlushInterval > 0 && Date.now() - sender.lastFlushTime >= sender.autoFlushInterval)
-    )) {
-        await sender.flush();
-    }
-}
-
-function sendTcp(sender, data) {
-    return new Promise((resolve, reject) => {
-        sender.socket.write(data, err => {
-            err ? reject(err) : sender.doResolve(resolve);
-        });
-    });
-}
-
-function checkCapacity(sender, data, base = 0) {
-    let length = base;
-    for (const str of data) {
-        length += Buffer.byteLength(str, 'utf8');
-    }
-    if (sender.position + length > sender.bufferSize) {
-        let newSize = sender.bufferSize;
-        do {
-            newSize += sender.bufferSize;
-        } while(sender.position + length > newSize);
-        sender.resize(newSize);
-    }
-}
-
-function compact(sender) {
-    if (sender.endOfLastRow > 0) {
-        sender.buffer.copy(sender.buffer, 0, sender.endOfLastRow, sender.position);
-        sender.position = sender.position - sender.endOfLastRow;
-        sender.endOfLastRow = 0;
-
-        sender.lastFlushTime = Date.now();
-        sender.pendingRowCount = 0;
-    }
-}
-
-function writeColumn(sender, name, value, writeValue, valueType) {
-    if (typeof name !== 'string') {
-        throw new Error(`Column name must be a string, received ${typeof name}`);
-    }
-    if (valueType != null && typeof value !== valueType) {
-        throw new Error(`Column value must be of type ${valueType}, received ${typeof value}`);
-    }
-    if (!sender.hasTable) {
-        throw new Error('Column can be set only after table name is set');
-    }
-    checkCapacity(sender, [name], 2 + name.length);
-    write(sender, sender.hasColumns ? ',' : ' ');
-    validateColumnName(name, sender.maxNameLength);
-    writeEscaped(sender, name);
-    write(sender, '=');
-    writeValue();
-    sender.hasColumns = true;
-}
-
-function write(sender, data) {
-    sender.position += sender.buffer.write(data, sender.position);
-    if (sender.position > sender.bufferSize) {
-        throw new Error(`Buffer overflow [position=${sender.position}, bufferSize=${sender.bufferSize}]`);
-    }
-}
-
-function writeEscaped(sender, data, quoted = false) {
-    for (const ch of data) {
-        if (ch > '\\') {
-            write(sender, ch);
-            continue;
-        }
-
-        switch (ch) {
-            case ' ':
-            case ',':
-            case '=':
-                if (!quoted) {
-                    write(sender, '\\');
-                }
-                write(sender, ch);
-                break;
-            case '\n':
-            case '\r':
-                write(sender, '\\');
-                write(sender, ch);
-                break;
-            case '"':
-                if (quoted) {
-                    write(sender, '\\');
-                }
-                write(sender, ch);
-                break;
-            case '\\':
-                write(sender, '\\\\');
-                break;
-            default:
-                write(sender, ch);
-                break;
-        }
-    }
-}
-
-function timestampToMicros(timestamp, unit) {
-    switch (unit) {
-        case 'ns':
-            return timestamp / 1000n;
-        case 'us':
-            return timestamp;
-        case 'ms':
-            return timestamp * 1000n;
-        default:
-            throw new Error('Unknown timestamp unit: ' + unit);
-    }
-}
-
-function timestampToNanos(timestamp, unit) {
-    switch (unit) {
-        case 'ns':
-            return timestamp;
-        case 'us':
-            return timestamp * 1000n;
-        case 'ms':
-            return timestamp * 1000_000n;
-        default:
-            throw new Error('Unknown timestamp unit: ' + unit);
-    }
-}
-
-function initSenderOptions(options) {
-    if (!options) {
-        options = {};
-    }
-
-    // defaults to TCP for backwards compatibility
-    if (!options.protocol) {
-        options.protocol = TCP;
-    }
-
-    // deal with deprecated options
-    if (options.copyBuffer) {
-        options.copy_buffer = options.copyBuffer;
-        options.copyBuffer = undefined;
-    }
-    if (options.bufferSize) {
-        options.init_buf_size = options.bufferSize;
-        options.bufferSize = undefined;
-    }
-    return options;
-}
-
-function constructAuth(options) {
-    if (!options.username && !options.token && !options.password) {
-        // no intention to authenticate
-        return;
-    }
-    if (!options.username || !options.token) {
-        throw new Error('TCP transport requires a username and a private key for authentication, ' +
-            'please, specify the \'username\' and \'token\' config options');
-    }
-
-    options.auth = {
-        keyId: options.username,
-        token: options.token
-    };
-}
-
-function constructJwk(options) {
-    if (options.auth) {
-        if (!options.auth.keyId) {
-            throw new Error('Missing username, please, specify the \'keyId\' property of the \'auth\' config option. ' +
-                'For example: new Sender({auth: {keyId: \'username\', token: \'private key\'}})');
-        }
-        if (typeof options.auth.keyId !== 'string') {
-            throw new Error('Please, specify the \'keyId\' property of the \'auth\' config option as a string. ' +
-                'For example: new Sender({auth: {keyId: \'username\', token: \'private key\'}})');
-        }
-        if (!options.auth.token) {
-            throw new Error('Missing private key, please, specify the \'token\' property of the \'auth\' config option. ' +
-                'For example: new Sender({auth: {keyId: \'username\', token: \'private key\'}})');
-        }
-        if (typeof options.auth.token !== 'string') {
-            throw new Error('Please, specify the \'token\' property of the \'auth\' config option as a string. ' +
-                'For example: new Sender({auth: {keyId: \'username\', token: \'private key\'}})');
-        }
-
-        return {
-            kid: options.auth.keyId,
-            d: options.auth.token,
-            ...PUBLIC_KEY,
-            kty: 'EC',
-            crv: 'P-256'
-        };
-    } else {
-        return options.jwk;
-    }
-}
-
-function sleep(ms) {
-    return new Promise(resolve => setTimeout(resolve, ms));
-}
-
-exports.Sender = Sender;
-exports.DEFAULT_BUFFER_SIZE = DEFAULT_BUFFER_SIZE;
-exports.DEFAULT_MAX_BUFFER_SIZE = DEFAULT_MAX_BUFFER_SIZE;
-
-
-
-
- - - -
- -
- Documentation generated by - JSDoc 4.0.2 on Wed Apr 17 - 2024 03:38:42 GMT+0100 (British Summer Time) -
- - - - - diff --git a/docs/styles/jsdoc-default.css b/docs/styles/jsdoc-default.css deleted file mode 100644 index 7d1729d..0000000 --- a/docs/styles/jsdoc-default.css +++ /dev/null @@ -1,358 +0,0 @@ -@font-face { - font-family: 'Open Sans'; - font-weight: normal; - font-style: normal; - src: url('../fonts/OpenSans-Regular-webfont.eot'); - src: - local('Open Sans'), - local('OpenSans'), - url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), - url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), - url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); -} - -@font-face { - font-family: 'Open Sans Light'; - font-weight: normal; - font-style: normal; - src: url('../fonts/OpenSans-Light-webfont.eot'); - src: - local('Open Sans Light'), - local('OpenSans Light'), - url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), - url('../fonts/OpenSans-Light-webfont.woff') format('woff'), - url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); -} - -html -{ - overflow: auto; - background-color: #fff; - font-size: 14px; -} - -body -{ - font-family: 'Open Sans', sans-serif; - line-height: 1.5; - color: #4d4e53; - background-color: white; -} - -a, a:visited, a:active { - color: #0095dd; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -header -{ - display: block; - padding: 0px 4px; -} - -tt, code, kbd, samp { - font-family: Consolas, Monaco, 'Andale Mono', monospace; -} - -.class-description { - font-size: 130%; - line-height: 140%; - margin-bottom: 1em; - margin-top: 1em; -} - -.class-description:empty { - margin: 0; -} - -#main { - float: left; - width: 70%; -} - -article dl { - margin-bottom: 40px; -} - -article img { - max-width: 100%; -} - -section -{ - display: block; - background-color: #fff; - padding: 12px 24px; - border-bottom: 1px solid #ccc; - margin-right: 30px; -} - -.variation { - display: none; -} - -.signature-attributes { - font-size: 60%; - color: #aaa; - font-style: italic; - font-weight: lighter; -} - -nav -{ - display: block; - float: right; - margin-top: 28px; - width: 30%; - box-sizing: border-box; - border-left: 1px solid #ccc; - padding-left: 16px; -} - -nav ul { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; - font-size: 100%; - line-height: 17px; - padding: 0; - margin: 0; - list-style-type: none; -} - -nav ul a, nav ul a:visited, nav ul a:active { - font-family: Consolas, Monaco, 'Andale Mono', monospace; - line-height: 18px; - color: #4D4E53; -} - -nav h3 { - margin-top: 12px; -} - -nav li { - margin-top: 6px; -} - -footer { - display: block; - padding: 6px; - margin-top: 12px; - font-style: italic; - font-size: 90%; -} - -h1, h2, h3, h4 { - font-weight: 200; - margin: 0; -} - -h1 -{ - font-family: 'Open Sans Light', sans-serif; - font-size: 48px; - letter-spacing: -2px; - margin: 12px 24px 20px; -} - -h2, h3.subsection-title -{ - font-size: 30px; - font-weight: 700; - letter-spacing: -1px; - margin-bottom: 12px; -} - -h3 -{ - font-size: 24px; - letter-spacing: -0.5px; - margin-bottom: 12px; -} - -h4 -{ - font-size: 18px; - letter-spacing: -0.33px; - margin-bottom: 12px; - color: #4d4e53; -} - -h5, .container-overview .subsection-title -{ - font-size: 120%; - font-weight: bold; - letter-spacing: -0.01em; - margin: 8px 0 3px 0; -} - -h6 -{ - font-size: 100%; - letter-spacing: -0.01em; - margin: 6px 0 3px 0; - font-style: italic; -} - -table -{ - border-spacing: 0; - border: 0; - border-collapse: collapse; -} - -td, th -{ - border: 1px solid #ddd; - margin: 0px; - text-align: left; - vertical-align: top; - padding: 4px 6px; - display: table-cell; -} - -thead tr -{ - background-color: #ddd; - font-weight: bold; -} - -th { border-right: 1px solid #aaa; } -tr > th:last-child { border-right: 1px solid #ddd; } - -.ancestors, .attribs { color: #999; } -.ancestors a, .attribs a -{ - color: #999 !important; - text-decoration: none; -} - -.clear -{ - clear: both; -} - -.important -{ - font-weight: bold; - color: #950B02; -} - -.yes-def { - text-indent: -1000px; -} - -.type-signature { - color: #aaa; -} - -.name, .signature { - font-family: Consolas, Monaco, 'Andale Mono', monospace; -} - -.details { margin-top: 14px; border-left: 2px solid #DDD; } -.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } -.details dd { margin-left: 70px; } -.details ul { margin: 0; } -.details ul { list-style-type: none; } -.details li { margin-left: 30px; padding-top: 6px; } -.details pre.prettyprint { margin: 0 } -.details .object-value { padding-top: 0; } - -.description { - margin-bottom: 1em; - margin-top: 1em; -} - -.code-caption -{ - font-style: italic; - font-size: 107%; - margin: 0; -} - -.source -{ - border: 1px solid #ddd; - width: 80%; - overflow: auto; -} - -.prettyprint.source { - width: inherit; -} - -.source code -{ - font-size: 100%; - line-height: 18px; - display: block; - padding: 4px 12px; - margin: 0; - background-color: #fff; - color: #4D4E53; -} - -.prettyprint code span.line -{ - display: inline-block; -} - -.prettyprint.linenums -{ - padding-left: 70px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.prettyprint.linenums ol -{ - padding-left: 0; -} - -.prettyprint.linenums li -{ - border-left: 3px #ddd solid; -} - -.prettyprint.linenums li.selected, -.prettyprint.linenums li.selected * -{ - background-color: lightyellow; -} - -.prettyprint.linenums li * -{ - -webkit-user-select: text; - -moz-user-select: text; - -ms-user-select: text; - user-select: text; -} - -.params .name, .props .name, .name code { - color: #4D4E53; - font-family: Consolas, Monaco, 'Andale Mono', monospace; - font-size: 100%; -} - -.params td.description > p:first-child, -.props td.description > p:first-child -{ - margin-top: 0; - padding-top: 0; -} - -.params td.description > p:last-child, -.props td.description > p:last-child -{ - margin-bottom: 0; - padding-bottom: 0; -} - -.disabled { - color: #454545; -} diff --git a/docs/styles/prettify-jsdoc.css b/docs/styles/prettify-jsdoc.css deleted file mode 100644 index 5a2526e..0000000 --- a/docs/styles/prettify-jsdoc.css +++ /dev/null @@ -1,111 +0,0 @@ -/* JSDoc prettify.js theme */ - -/* plain text */ -.pln { - color: #000000; - font-weight: normal; - font-style: normal; -} - -/* string content */ -.str { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a keyword */ -.kwd { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* a comment */ -.com { - font-weight: normal; - font-style: italic; -} - -/* a type name */ -.typ { - color: #000000; - font-weight: normal; - font-style: normal; -} - -/* a literal value */ -.lit { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* punctuation */ -.pun { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* lisp open bracket */ -.opn { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* lisp close bracket */ -.clo { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* a markup tag name */ -.tag { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a markup attribute name */ -.atn { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a markup attribute value */ -.atv { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a declaration */ -.dec { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* a variable name */ -.var { - color: #000000; - font-weight: normal; - font-style: normal; -} - -/* a function name */ -.fun { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* Specify class=linenums on a pre to get line numbering */ -ol.linenums { - margin-top: 0; - margin-bottom: 0; -} diff --git a/docs/styles/prettify-tomorrow.css b/docs/styles/prettify-tomorrow.css deleted file mode 100644 index b6f92a7..0000000 --- a/docs/styles/prettify-tomorrow.css +++ /dev/null @@ -1,132 +0,0 @@ -/* Tomorrow Theme */ -/* Original theme - https://github.com/chriskempson/tomorrow-theme */ -/* Pretty printing styles. Used with prettify.js. */ -/* SPAN elements with the classes below are added by prettyprint. */ -/* plain text */ -.pln { - color: #4d4d4c; } - -@media screen { - /* string content */ - .str { - color: #718c00; } - - /* a keyword */ - .kwd { - color: #8959a8; } - - /* a comment */ - .com { - color: #8e908c; } - - /* a type name */ - .typ { - color: #4271ae; } - - /* a literal value */ - .lit { - color: #f5871f; } - - /* punctuation */ - .pun { - color: #4d4d4c; } - - /* lisp open bracket */ - .opn { - color: #4d4d4c; } - - /* lisp close bracket */ - .clo { - color: #4d4d4c; } - - /* a markup tag name */ - .tag { - color: #c82829; } - - /* a markup attribute name */ - .atn { - color: #f5871f; } - - /* a markup attribute value */ - .atv { - color: #3e999f; } - - /* a declaration */ - .dec { - color: #f5871f; } - - /* a variable name */ - .var { - color: #c82829; } - - /* a function name */ - .fun { - color: #4271ae; } } -/* Use higher contrast and text-weight for printable form. */ -@media print, projection { - .str { - color: #060; } - - .kwd { - color: #006; - font-weight: bold; } - - .com { - color: #600; - font-style: italic; } - - .typ { - color: #404; - font-weight: bold; } - - .lit { - color: #044; } - - .pun, .opn, .clo { - color: #440; } - - .tag { - color: #006; - font-weight: bold; } - - .atn { - color: #404; } - - .atv { - color: #060; } } -/* Style */ -/* -pre.prettyprint { - background: white; - font-family: Consolas, Monaco, 'Andale Mono', monospace; - font-size: 12px; - line-height: 1.5; - border: 1px solid #ccc; - padding: 10px; } -*/ - -/* Specify class=linenums on a pre to get line numbering */ -ol.linenums { - margin-top: 0; - margin-bottom: 0; } - -/* IE indents via margin-left */ -li.L0, -li.L1, -li.L2, -li.L3, -li.L4, -li.L5, -li.L6, -li.L7, -li.L8, -li.L9 { - /* */ } - -/* Alternate shading for lines */ -li.L1, -li.L3, -li.L5, -li.L7, -li.L9 { - /* */ } diff --git a/docs/types/ExtraOptions.html b/docs/types/ExtraOptions.html new file mode 100644 index 0000000..fb8448c --- /dev/null +++ b/docs/types/ExtraOptions.html @@ -0,0 +1,3 @@ +ExtraOptions | QuestDB Node.js Client - v4.0.0

Type Alias ExtraOptions

type ExtraOptions = {
    log?: Logger;
    agent?: Agent | http.Agent | https.Agent;
}
Index

Properties

Properties

log?: Logger
agent?: Agent | http.Agent | https.Agent
diff --git a/docs/types/Logger.html b/docs/types/Logger.html new file mode 100644 index 0000000..c479742 --- /dev/null +++ b/docs/types/Logger.html @@ -0,0 +1,4 @@ +Logger | QuestDB Node.js Client - v4.0.0

Type Alias Logger

Logger: (
    level: "error" | "warn" | "info" | "debug",
    message: string | Error,
) => void

Logger function type definition.

+

Type declaration

    • (level: "error" | "warn" | "info" | "debug", message: string | Error): void
    • Parameters

      • level: "error" | "warn" | "info" | "debug"

        The log level for the message

        +
      • message: string | Error

        The message to log, either a string or Error object

        +

      Returns void

diff --git a/docs/types/TimestampUnit.html b/docs/types/TimestampUnit.html new file mode 100644 index 0000000..61245ad --- /dev/null +++ b/docs/types/TimestampUnit.html @@ -0,0 +1,2 @@ +TimestampUnit | QuestDB Node.js Client - v4.0.0

Type Alias TimestampUnit

TimestampUnit: "ns" | "us" | "ms"

Supported timestamp units for QuestDB operations.

+
diff --git a/examples.manifest.yaml b/examples.manifest.yaml index 0c5454d..428a4dd 100644 --- a/examples.manifest.yaml +++ b/examples.manifest.yaml @@ -31,7 +31,7 @@ port: 9009 - name: ilp-from-conf lang: javascript - path: examples/from_conf.js + path: examples/basic.js header: |- NodeJS client library [repo](https://github.com/questdb/nodejs-questdb-client). conf: http::addr=localhost:9000 diff --git a/examples/arrays.ts b/examples/arrays.ts new file mode 100644 index 0000000..b0ed984 --- /dev/null +++ b/examples/arrays.ts @@ -0,0 +1,52 @@ +import { Sender } from "@questdb/nodejs-client"; + +async function run() { + // create a sender + const sender = await Sender.fromConfig('http::addr=localhost:9000'); + + // order book snapshots to ingest + const orderBooks = [ + { + symbol: 'BTC-USD', + exchange: 'Coinbase', + timestamp: Date.now(), + bidPrices: [50100.25, 50100.20, 50100.15, 50100.10, 50100.05], + bidSizes: [0.5, 1.2, 2.1, 0.8, 3.5], + askPrices: [50100.30, 50100.35, 50100.40, 50100.45, 50100.50], + askSizes: [0.6, 1.5, 1.8, 2.2, 4.0] + }, + { + symbol: 'ETH-USD', + exchange: 'Coinbase', + timestamp: Date.now(), + bidPrices: [2850.50, 2850.45, 2850.40, 2850.35, 2850.30], + bidSizes: [5.0, 8.2, 12.5, 6.8, 15.0], + askPrices: [2850.55, 2850.60, 2850.65, 2850.70, 2850.75], + askSizes: [4.5, 7.8, 10.2, 8.5, 20.0] + } + ]; + + try { + // add rows to the buffer of the sender + for (const orderBook of orderBooks) { + await sender + .table('order_book_l2') + .symbol('symbol', orderBook.symbol) + .symbol('exchange', orderBook.exchange) + .arrayColumn('bid_prices', orderBook.bidPrices) + .arrayColumn('bid_sizes', orderBook.bidSizes) + .arrayColumn('ask_prices', orderBook.askPrices) + .arrayColumn('ask_sizes', orderBook.askSizes) + .at(orderBook.timestamp, 'ms'); + } + + // flush the buffer of the sender, sending the data to QuestDB + // the buffer is cleared after the data is sent, and the sender is ready to accept new data + await sender.flush(); + } finally { + // close the connection after all rows ingested + await sender.close(); + } +} + +run().then(console.log).catch(console.error); diff --git a/examples/auth.js b/examples/auth.js index 543a313..1ed5aac 100644 --- a/examples/auth.js +++ b/examples/auth.js @@ -2,24 +2,16 @@ const { Sender } = require("@questdb/nodejs-client"); async function run() { // authentication details - const CLIENT_ID = "admin"; - const PRIVATE_KEY = "ZRxmCOQBpZoj2fZ-lEtqzVDkCre_ouF3ePpaQNDwoQk"; - const AUTH = { - keyId: CLIENT_ID, - token: PRIVATE_KEY, - }; + const USER = "admin"; + const PWD = "quest"; // pass the authentication details to the sender - const sender = new Sender({ - protocol: "tcp", - host: "127.0.0.1", - port: 9009, - bufferSize: 4096, - auth: AUTH, - }); - await sender.connect(); + // for secure connection use 'https' protocol instead of 'http' + const sender = await Sender.fromConfig( + `http::addr=127.0.0.1:9000;username=${USER};password=${PWD}` + ); - // send the data over the authenticated connection + // add rows to the buffer of the sender await sender .table("trades") .symbol("symbol", "ETH-USD") @@ -28,15 +20,6 @@ async function run() { .floatColumn("amount", 0.00044) .at(Date.now(), "ms"); - // add rows to the buffer of the sender - await sender - .table("trades") - .symbol("symbol", "BTC-USD") - .symbol("side", "sell") - .floatColumn("price", 39269.98) - .floatColumn("amount", 0.001) - .at(Date.now(), "ms"); - // flush the buffer of the sender, sending the data to QuestDB await sender.flush(); @@ -44,4 +27,4 @@ async function run() { await sender.close(); } -run().catch(console.error); +run().catch(console.error); \ No newline at end of file diff --git a/examples/auth_tcp.js b/examples/auth_tcp.js new file mode 100644 index 0000000..c806ba6 --- /dev/null +++ b/examples/auth_tcp.js @@ -0,0 +1,30 @@ +const { Sender } = require("@questdb/nodejs-client"); + +async function run() { + // authentication details + const CLIENT_ID = "admin"; + const PRIVATE_KEY = "ZRxmCOQBpZoj2fZ-lEtqzVDkCre_ouF3ePpaQNDwoQk"; + + // pass the authentication details to the sender + const sender = await Sender.fromConfig( + `tcp::addr=127.0.0.1:9009;username=${CLIENT_ID};token=${PRIVATE_KEY}` + ); + await sender.connect(); + + // add rows to the buffer of the sender + await sender + .table("trades") + .symbol("symbol", "BTC-USD") + .symbol("side", "sell") + .floatColumn("price", 39269.98) + .floatColumn("amount", 0.001) + .at(Date.now(), "ms"); + + // flush the buffer of the sender, sending the data to QuestDB + await sender.flush(); + + // close the connection after all rows ingested + await sender.close(); +} + +run().catch(console.error); \ No newline at end of file diff --git a/examples/auth_tls.js b/examples/auth_tls.js index e5e1146..8bf39dd 100644 --- a/examples/auth_tls.js +++ b/examples/auth_tls.js @@ -2,24 +2,16 @@ const { Sender } = require("@questdb/nodejs-client"); async function run() { // authentication details - const CLIENT_ID = "admin"; - const PRIVATE_KEY = "ZRxmCOQBpZoj2fZ-lEtqzVDkCre_ouF3ePpaQNDwoQk"; - const AUTH = { - keyId: CLIENT_ID, - token: PRIVATE_KEY, - }; + const USER = "admin"; + const PWD = "quest"; // pass the authentication details to the sender - const sender = new Sender({ - protocol: "tcps", - host: "127.0.0.1", - port: 9009, - bufferSize: 4096, - auth: AUTH, - }); - await sender.connect(); + // for secure connection use 'https' protocol instead of 'http' + const sender = await Sender.fromConfig( + `https::addr=127.0.0.1:9000;username=${USER};password=${PWD}` + ); - // send the data over the authenticated connection + // add rows to the buffer of the sender await sender .table("trades") .symbol("symbol", "ETH-USD") @@ -28,15 +20,6 @@ async function run() { .floatColumn("amount", 0.00044) .at(Date.now(), "ms"); - // add rows to the buffer of the sender - await sender - .table("trades") - .symbol("symbol", "BTC-USD") - .symbol("side", "sell") - .floatColumn("price", 39269.98) - .floatColumn("amount", 0.001) - .at(Date.now(), "ms"); - // flush the buffer of the sender, sending the data to QuestDB await sender.flush(); @@ -44,4 +27,4 @@ async function run() { await sender.close(); } -run().catch(console.error); +run().catch(console.error); \ No newline at end of file diff --git a/examples/auth_tls_tcp.js b/examples/auth_tls_tcp.js new file mode 100644 index 0000000..c041f97 --- /dev/null +++ b/examples/auth_tls_tcp.js @@ -0,0 +1,30 @@ +const { Sender } = require("@questdb/nodejs-client"); + +async function run() { + // authentication details + const CLIENT_ID = "admin"; + const PRIVATE_KEY = "ZRxmCOQBpZoj2fZ-lEtqzVDkCre_ouF3ePpaQNDwoQk"; + + // pass the authentication details to the sender + const sender = await Sender.fromConfig( + `tcps::addr=127.0.0.1:9009;username=${CLIENT_ID};token=${PRIVATE_KEY}` + ); + await sender.connect(); + + // add rows to the buffer of the sender + await sender + .table("trades") + .symbol("symbol", "BTC-USD") + .symbol("side", "sell") + .floatColumn("price", 39269.98) + .floatColumn("amount", 0.001) + .at(Date.now(), "ms"); + + // flush the buffer of the sender, sending the data to QuestDB + await sender.flush(); + + // close the connection after all rows ingested + await sender.close(); +} + +run().catch(console.error); \ No newline at end of file diff --git a/examples/basic.js b/examples/basic.js index 83b43d5..313fd01 100644 --- a/examples/basic.js +++ b/examples/basic.js @@ -1,22 +1,16 @@ const { Sender } = require("@questdb/nodejs-client"); async function run() { - // create a sender with a 4KB buffer - const sender = new Sender({ - protocol: "tcp", - host: "127.0.0.1", - port: 9009, - bufferSize: 4096, - }); - await sender.connect(); + // create a sender using HTTP protocol + const sender = await Sender.fromConfig("http::addr=127.0.0.1:9000"); // add rows to the buffer of the sender await sender .table("trades") - .symbol("symbol", "ETH-USD") + .symbol("symbol", "BTC-USD") .symbol("side", "sell") - .floatColumn("price", 2615.54) - .floatColumn("amount", 0.00044) + .floatColumn("price", 39269.98) + .floatColumn("amount", 0.011) .at(Date.now(), "ms"); // flush the buffer of the sender, sending the data to QuestDB diff --git a/examples/from_conf.js b/examples/from_conf.js deleted file mode 100644 index e6ef5e7..0000000 --- a/examples/from_conf.js +++ /dev/null @@ -1,25 +0,0 @@ -const { Sender } = require("@questdb/nodejs-client"); - -async function run() { - // create a sender using HTTP protocol - const sender = Sender.fromConfig("http::addr=127.0.0.1:9000"); - - // add rows to the buffer of the sender - await sender - .table("trades") - .symbol("symbol", "ETH-USD") - .symbol("side", "sell") - .floatColumn("price", 2615.54) - .floatColumn("amount", 0.00044) - .at(Date.now(), "ms"); - - // flush the buffer of the sender, sending the data to QuestDB - // the buffer is cleared after the data is sent, and the sender is ready to accept new data - await sender.flush(); - - // close the connection after all rows ingested - // unflushed data will be lost - await sender.close(); -} - -run().then(console.log).catch(console.error); diff --git a/examples/workers.js b/examples/workers.ts similarity index 86% rename from examples/workers.js rename to examples/workers.ts index fb7b7d2..f846527 100644 --- a/examples/workers.js +++ b/examples/workers.ts @@ -1,10 +1,5 @@ -const { Sender } = require("@questdb/nodejs-client"); -const { - Worker, - isMainThread, - parentPort, - workerData, -} = require("worker_threads"); +import { Sender } from "@questdb/nodejs-client"; +import { Worker, isMainThread, parentPort, workerData } from "worker_threads"; // fake venue // generates random prices and amounts for a ticker for max 5 seconds, then the feed closes @@ -34,7 +29,7 @@ async function run() { const tickers = ["ETH-USD", "BTC-USD", "SOL-USD", "DOGE-USD"]; // main thread to start a worker thread for each ticker for (let ticker of tickers) { - const worker = new Worker(__filename, { workerData: { ticker: ticker } }) + new Worker(__filename, { workerData: { ticker: ticker } }) .on("error", (err) => { throw err; }) @@ -48,7 +43,7 @@ async function run() { } else { // it is important that each worker has a dedicated sender object // threads cannot share the sender because they would write into the same buffer - const sender = Sender.fromConfig("http::addr=127.0.0.1:9000"); + const sender = await Sender.fromConfig("http::addr=127.0.0.1:9000"); // subscribe for the market data of the ticker assigned to the worker // ingest each price update into the database using the sender @@ -73,11 +68,11 @@ async function run() { } } -function sleep(ms) { +function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } -function rndInt(limit) { +function rndInt(limit: number) { return Math.floor(Math.random() * limit + 1); } diff --git a/package.json b/package.json index 3b6b129..8852aff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@questdb/nodejs-client", - "version": "3.0.0", + "version": "4.0.0", "description": "QuestDB Node.js Client", "scripts": { "test": "vitest", @@ -8,7 +8,7 @@ "eslint": "eslint src/**", "typecheck": "tsc --noEmit", "format": "prettier --write '{src,test}/**/*.{ts,js,json}'", - "docs": "pnpm run build && jsdoc ./dist/cjs/index.js README.md -d docs", + "docs": "typedoc --out docs src/index.ts", "preview:docs": "serve docs" }, "files": [ @@ -36,13 +36,14 @@ "homepage": "https://questdb.github.io/nodejs-questdb-client", "devDependencies": { "@eslint/js": "^9.16.0", + "@microsoft/tsdoc": "^0.15.1", "@types/node": "^22.15.17", "bunchee": "^6.5.1", "eslint": "^9.26.0", - "jsdoc": "^4.0.4", "prettier": "^3.5.3", "serve": "^14.2.4", "testcontainers": "^10.25.0", + "typedoc": "^0.28.9", "typescript": "^5.7.2", "typescript-eslint": "^8.32.0", "vitest": "^3.1.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c9982c5..d824b63 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,9 @@ importers: '@eslint/js': specifier: ^9.16.0 version: 9.16.0 + '@microsoft/tsdoc': + specifier: ^0.15.1 + version: 0.15.1 '@types/node': specifier: ^22.15.17 version: 22.15.17 @@ -24,9 +27,6 @@ importers: eslint: specifier: ^9.26.0 version: 9.26.0 - jsdoc: - specifier: ^4.0.4 - version: 4.0.4 prettier: specifier: ^3.5.3 version: 3.5.3 @@ -36,6 +36,9 @@ importers: testcontainers: specifier: ^10.25.0 version: 10.25.0 + typedoc: + specifier: ^0.28.9 + version: 0.28.9(typescript@5.7.2) typescript: specifier: ^5.7.2 version: 5.7.2 @@ -52,23 +55,10 @@ packages: resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.25.9': - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.9': resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} - '@babel/parser@7.26.3': - resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/types@7.26.3': - resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} - engines: {node: '>=6.9.0'} - '@balena/dockerignore@1.0.2': resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} @@ -265,6 +255,9 @@ packages: '@fastify/deepmerge@1.3.0': resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==} + '@gerrit0/mini-shiki@3.9.2': + resolution: {integrity: sha512-Tvsj+AOO4Z8xLRJK900WkyfxHsZQu+Zm1//oT1w443PO6RiYMoq/4NGOhaNuZoUMYsjKIAPVQ6eOFMddj6yphQ==} + '@grpc/grpc-js@1.13.3': resolution: {integrity: sha512-FTXHdOoPbZrBjlVLHuKbDZnsTxXv2BlHF57xw6LuThXacXvtkahEPED0CKMk6obZDf65Hv4k3z62eyPNpvinIg==} engines: {node: '>=12.10.0'} @@ -304,9 +297,8 @@ packages: '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} - '@jsdoc/salty@0.2.8': - resolution: {integrity: sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==} - engines: {node: '>=v12.0.0'} + '@microsoft/tsdoc@0.15.1': + resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} '@modelcontextprotocol/sdk@1.11.1': resolution: {integrity: sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ==} @@ -602,6 +594,21 @@ packages: cpu: [x64] os: [win32] + '@shikijs/engine-oniguruma@3.9.2': + resolution: {integrity: sha512-Vn/w5oyQ6TUgTVDIC/BrpXwIlfK6V6kGWDVVz2eRkF2v13YoENUvaNwxMsQU/t6oCuZKzqp9vqtEtEzKl9VegA==} + + '@shikijs/langs@3.9.2': + resolution: {integrity: sha512-X1Q6wRRQXY7HqAuX3I8WjMscjeGjqXCg/Sve7J2GWFORXkSrXud23UECqTBIdCSNKJioFtmUGJQNKtlMMZMn0w==} + + '@shikijs/themes@3.9.2': + resolution: {integrity: sha512-6z5lBPBMRfLyyEsgf6uJDHPa6NAGVzFJqH4EAZ+03+7sedYir2yJBRu2uPZOKmj43GyhVHWHvyduLDAwJQfDjA==} + + '@shikijs/types@3.9.2': + resolution: {integrity: sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@swc/core-darwin-arm64@1.11.24': resolution: {integrity: sha512-dhtVj0PC1APOF4fl5qT2neGjRLgHAAYfiVP8poJelhzhB/318bO+QCFWAiimcDoyMgpCXOhTp757gnoJJrheWA==} engines: {node: '>=10'} @@ -692,18 +699,12 @@ packages: '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/linkify-it@5.0.0': - resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} - - '@types/markdown-it@14.1.2': - resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} - - '@types/mdurl@2.0.0': - resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} - '@types/node@18.19.67': resolution: {integrity: sha512-wI8uHusga+0ZugNp0Ol/3BqQfEcCCNfojtO6Oou9iVNGPTL6QNSdnUdqq85fRgIorLhLMuPIKpsN98QE9Nh+KQ==} @@ -722,6 +723,9 @@ packages: '@types/ssh2@1.15.1': resolution: {integrity: sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==} + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@typescript-eslint/eslint-plugin@8.32.0': resolution: {integrity: sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -926,9 +930,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - bluebird@3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - body-parser@2.2.0: resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} engines: {node: '>=18'} @@ -1003,10 +1004,6 @@ packages: resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} engines: {node: '>=14.16'} - catharsis@0.9.0: - resolution: {integrity: sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==} - engines: {node: '>= 10'} - chai@5.2.0: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} engines: {node: '>=12'} @@ -1241,10 +1238,6 @@ packages: escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1588,14 +1581,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - js2xmlparser@4.0.2: - resolution: {integrity: sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==} - - jsdoc@4.0.4: - resolution: {integrity: sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==} - engines: {node: '>=12.0.0'} - hasBin: true - json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -1611,9 +1596,6 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - klaw@3.0.0: - resolution: {integrity: sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==} - lazystream@1.0.1: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} @@ -1654,24 +1636,16 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lunr@2.3.9: + resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - markdown-it-anchor@8.6.7: - resolution: {integrity: sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==} - peerDependencies: - '@types/markdown-it': '*' - markdown-it: '*' - markdown-it@14.1.0: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true - marked@4.3.0: - resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} - engines: {node: '>= 12'} - hasBin: true - math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -1999,9 +1973,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - requizzle@0.2.4: - resolution: {integrity: sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2286,6 +2257,13 @@ packages: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} + typedoc@0.28.9: + resolution: {integrity: sha512-aw45vwtwOl3QkUAmWCnLV9QW1xY+FSX2zzlit4MAfE99wX+Jij4ycnpbAWgBXsRrxmfs9LaYktg/eX5Bpthd3g==} + engines: {node: '>= 18', pnpm: '>= 10'} + hasBin: true + peerDependencies: + typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x + typescript-eslint@8.32.0: resolution: {integrity: sha512-UMq2kxdXCzinFFPsXc9o2ozIpYCCOiEC46MG3yEh5Vipq6BO27otTtEBZA1fQ66DulEUgE97ucQ/3YY66CPg0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2301,9 +2279,6 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - underscore@1.13.7: - resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} - undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -2432,9 +2407,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - xmlcreate@2.0.4: - resolution: {integrity: sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -2444,6 +2416,11 @@ packages: engines: {node: '>= 14'} hasBin: true + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -2477,18 +2454,8 @@ snapshots: picocolors: 1.1.1 optional: true - '@babel/helper-string-parser@7.25.9': {} - - '@babel/helper-validator-identifier@7.25.9': {} - - '@babel/parser@7.26.3': - dependencies: - '@babel/types': 7.26.3 - - '@babel/types@7.26.3': - dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier@7.25.9': + optional: true '@balena/dockerignore@1.0.2': {} @@ -2616,6 +2583,14 @@ snapshots: '@fastify/deepmerge@1.3.0': {} + '@gerrit0/mini-shiki@3.9.2': + dependencies: + '@shikijs/engine-oniguruma': 3.9.2 + '@shikijs/langs': 3.9.2 + '@shikijs/themes': 3.9.2 + '@shikijs/types': 3.9.2 + '@shikijs/vscode-textmate': 10.0.2 + '@grpc/grpc-js@1.13.3': dependencies: '@grpc/proto-loader': 0.7.15 @@ -2654,9 +2629,7 @@ snapshots: '@js-sdsl/ordered-map@4.4.2': {} - '@jsdoc/salty@0.2.8': - dependencies: - lodash: 4.17.21 + '@microsoft/tsdoc@0.15.1': {} '@modelcontextprotocol/sdk@1.11.1': dependencies: @@ -2874,6 +2847,26 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.40.2': optional: true + '@shikijs/engine-oniguruma@3.9.2': + dependencies: + '@shikijs/types': 3.9.2 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.9.2': + dependencies: + '@shikijs/types': 3.9.2 + + '@shikijs/themes@3.9.2': + dependencies: + '@shikijs/types': 3.9.2 + + '@shikijs/types@3.9.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + '@swc/core-darwin-arm64@1.11.24': optional: true @@ -2946,16 +2939,11 @@ snapshots: '@types/estree@1.0.7': {} - '@types/json-schema@7.0.15': {} - - '@types/linkify-it@5.0.0': {} - - '@types/markdown-it@14.1.2': + '@types/hast@3.0.4': dependencies: - '@types/linkify-it': 5.0.0 - '@types/mdurl': 2.0.0 + '@types/unist': 3.0.3 - '@types/mdurl@2.0.0': {} + '@types/json-schema@7.0.15': {} '@types/node@18.19.67': dependencies: @@ -2980,6 +2968,8 @@ snapshots: dependencies: '@types/node': 18.19.67 + '@types/unist@3.0.3': {} + '@typescript-eslint/eslint-plugin@8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.7.2))(eslint@9.26.0)(typescript@5.7.2)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -3227,8 +3217,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - bluebird@3.7.2: {} - body-parser@2.2.0: dependencies: bytes: 3.1.2 @@ -3329,10 +3317,6 @@ snapshots: camelcase@7.0.1: {} - catharsis@0.9.0: - dependencies: - lodash: 4.17.21 - chai@5.2.0: dependencies: assertion-error: 2.0.1 @@ -3565,8 +3549,6 @@ snapshots: escape-html@1.0.3: {} - escape-string-regexp@2.0.0: {} - escape-string-regexp@4.0.0: {} eslint-scope@8.3.0: @@ -3934,28 +3916,6 @@ snapshots: dependencies: argparse: 2.0.1 - js2xmlparser@4.0.2: - dependencies: - xmlcreate: 2.0.4 - - jsdoc@4.0.4: - dependencies: - '@babel/parser': 7.26.3 - '@jsdoc/salty': 0.2.8 - '@types/markdown-it': 14.1.2 - bluebird: 3.7.2 - catharsis: 0.9.0 - escape-string-regexp: 2.0.0 - js2xmlparser: 4.0.2 - klaw: 3.0.0 - markdown-it: 14.1.0 - markdown-it-anchor: 8.6.7(@types/markdown-it@14.1.2)(markdown-it@14.1.0) - marked: 4.3.0 - mkdirp: 1.0.4 - requizzle: 0.2.4 - strip-json-comments: 3.1.1 - underscore: 1.13.7 - json-buffer@3.0.1: {} json-schema-traverse@0.4.1: {} @@ -3968,10 +3928,6 @@ snapshots: dependencies: json-buffer: 3.0.1 - klaw@3.0.0: - dependencies: - graceful-fs: 4.2.11 - lazystream@1.0.1: dependencies: readable-stream: 2.3.8 @@ -4008,15 +3964,12 @@ snapshots: lru-cache@10.4.3: {} + lunr@2.3.9: {} + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 - markdown-it-anchor@8.6.7(@types/markdown-it@14.1.2)(markdown-it@14.1.0): - dependencies: - '@types/markdown-it': 14.1.2 - markdown-it: 14.1.0 - markdown-it@14.1.0: dependencies: argparse: 2.0.1 @@ -4026,8 +3979,6 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 - marked@4.3.0: {} - math-intrinsics@1.1.0: {} mdurl@2.0.0: {} @@ -4320,10 +4271,6 @@ snapshots: require-from-string@2.0.2: {} - requizzle@0.2.4: - dependencies: - lodash: 4.17.21 - resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -4708,6 +4655,15 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.1 + typedoc@0.28.9(typescript@5.7.2): + dependencies: + '@gerrit0/mini-shiki': 3.9.2 + lunr: 2.3.9 + markdown-it: 14.1.0 + minimatch: 9.0.5 + typescript: 5.7.2 + yaml: 2.8.1 + typescript-eslint@8.32.0(eslint@9.26.0)(typescript@5.7.2): dependencies: '@typescript-eslint/eslint-plugin': 8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.7.2))(eslint@9.26.0)(typescript@5.7.2) @@ -4722,8 +4678,6 @@ snapshots: uc.micro@2.1.0: {} - underscore@1.13.7: {} - undici-types@5.26.5: {} undici-types@6.21.0: {} @@ -4843,12 +4797,12 @@ snapshots: wrappy@1.0.2: {} - xmlcreate@2.0.4: {} - y18n@5.0.8: {} yaml@2.6.1: {} + yaml@2.8.1: {} + yargs-parser@21.1.1: {} yargs@17.7.2: diff --git a/src/buffer/base.ts b/src/buffer/base.ts index 6182a19..f791ffd 100644 --- a/src/buffer/base.ts +++ b/src/buffer/base.ts @@ -20,7 +20,7 @@ import { const DEFAULT_MAX_NAME_LENGTH = 127; /** - * Abstract base class for SenderBuffer implementations.
+ * Abstract base class for sender buffer implementations.
* Provides common functionality for writing data into the buffer. */ abstract class SenderBufferBase implements SenderBuffer { diff --git a/src/buffer/bufferv1.ts b/src/buffer/bufferv1.ts index 16dfecf..64cfae2 100644 --- a/src/buffer/bufferv1.ts +++ b/src/buffer/bufferv1.ts @@ -4,7 +4,7 @@ import { SenderBuffer } from "./index"; import { SenderBufferBase } from "./base"; /** - * Buffer implementation for protocol version 1. + * Buffer implementation for protocol version 1.
* Sends floating point numbers in their text form. */ class SenderBufferV1 extends SenderBufferBase { diff --git a/src/buffer/bufferv2.ts b/src/buffer/bufferv2.ts index 9f471cb..711a57a 100644 --- a/src/buffer/bufferv2.ts +++ b/src/buffer/bufferv2.ts @@ -16,8 +16,8 @@ const ENTITY_TYPE_DOUBLE: number = 16; const EQUALS_SIGN: number = "=".charCodeAt(0); /** - * Buffer implementation for protocol version 2. - * Sends floating point numbers in binary form. + * Buffer implementation for protocol version 2.
+ * Sends floating point numbers in binary form, and provides support for arrays. */ class SenderBufferV2 extends SenderBufferBase { /** diff --git a/src/buffer/index.ts b/src/buffer/index.ts index f35c78a..d4ddc71 100644 --- a/src/buffer/index.ts +++ b/src/buffer/index.ts @@ -19,10 +19,8 @@ const DEFAULT_MAX_BUFFER_SIZE = 104857600; // 100 MB /** * Factory function to create a SenderBuffer instance based on the protocol version. - * - * @param {SenderOptions} options - Sender configuration object.
- * See SenderOptions documentation for detailed description of configuration options. - * + * @param options - Sender configuration object. + * See {@link SenderOptions} documentation for detailed description of configuration options. * @returns A SenderBuffer instance appropriate for the specified protocol version * @throws Error if protocol version is not specified or is unsupported */ @@ -41,91 +39,89 @@ function createBuffer(options: SenderOptions): SenderBuffer { ); default: throw new Error( - "Unsupported protocol version: " + options.protocol_version, + `Unsupported protocol version: ${options.protocol_version}`, ); } } /** - * Buffer used by the Sender. + * Buffer used by the Sender for data serialization.
+ * Provides methods for writing different data types into the buffer. */ interface SenderBuffer { /** - * Resets the buffer, data sitting in the buffer will be lost.
+ * Resets the buffer, data sitting in the buffer will be lost. * In other words it clears the buffer, and sets the writing position to the beginning of the buffer. - * - * @return {Sender} Returns with a reference to this sender. + * @returns Returns with a reference to this buffer. */ reset(): SenderBuffer; /** - * @return {Buffer} Returns a cropped buffer, or null if there is nothing to send.
+ * Returns a cropped buffer, or null if there is nothing to send. * The returned buffer is backed by this buffer instance, meaning the view can change as the buffer is mutated. * Used only in tests to assert the buffer's content. + * @param pos - Optional position parameter + * @returns A view of the buffer */ toBufferView(pos?: number): Buffer; /** - * @return {Buffer} Returns a cropped buffer ready to send to the server, or null if there is nothing to send.
+ * Returns a cropped buffer ready to send to the server, or null if there is nothing to send. * The returned buffer is a copy of this buffer. * It also compacts the buffer. + * @param pos - Optional position parameter + * @returns A copy of the buffer ready to send, or null */ toBufferNew(pos?: number): Buffer | null; /** * Writes the table name into the buffer. - * - * @param {string} table - Table name. - * @return {Sender} Returns with a reference to this sender. + * @param table - Table name. + * @returns Returns with a reference to this buffer. */ table(table: string): SenderBuffer; /** - * Writes a symbol name and value into the buffer.
+ * Writes a symbol name and value into the buffer. * Use it to insert into SYMBOL columns. - * - * @param {string} name - Symbol name. - * @param {unknown} value - Symbol value, toString() is called to extract the actual symbol value from the parameter. - * @return {Sender} Returns with a reference to this sender. + * @param name - Symbol name. + * @param value - Symbol value, toString() is called to extract the actual symbol value from the parameter. + * @returns Returns with a reference to this buffer. */ symbol(name: string, value: unknown): SenderBuffer; /** - * Writes a string column with its value into the buffer.
+ * Writes a string column with its value into the buffer. * Use it to insert into VARCHAR and STRING columns. - * - * @param {string} name - Column name. - * @param {string} value - Column value, accepts only string values. - * @return {Sender} Returns with a reference to this sender. + * @param name - Column name. + * @param value - Column value, accepts only string values. + * @returns Returns with a reference to this buffer. */ stringColumn(name: string, value: string): SenderBuffer; /** - * Writes a boolean column with its value into the buffer.
+ * Writes a boolean column with its value into the buffer. * Use it to insert into BOOLEAN columns. - * - * @param {string} name - Column name. - * @param {boolean} value - Column value, accepts only boolean values. - * @return {Sender} Returns with a reference to this sender. + * @param name - Column name. + * @param value - Column value, accepts only boolean values. + * @returns Returns with a reference to this buffer. */ booleanColumn(name: string, value: boolean): SenderBuffer; /** - * Writes a 64-bit floating point value into the buffer.
+ * Writes a 64-bit floating point value into the buffer. * Use it to insert into DOUBLE or FLOAT database columns. - * - * @param {string} name - Column name. - * @param {number} value - Column value, accepts only number values. - * @return {Sender} Returns with a reference to this sender. + * @param name - Column name. + * @param value - Column value, accepts only number values. + * @returns Returns with a reference to this buffer. */ floatColumn(name: string, value: number): SenderBuffer; /** * Writes an array column with its values into the buffer. - * - * @param {string} name - Column name - * @param {unknown[]} value - Array values to write (currently supports double arrays) - * @returns {Sender} Returns with a reference to this buffer. + * @param name - Column name + * @param value - Array values to write (currently supports double arrays) + * @returns Returns with a reference to this buffer. * @throws Error if arrays are not supported by the buffer implementation, or array validation fails: * - value is not an array * - or the shape of the array is irregular: the length of sub-arrays are different @@ -134,24 +130,22 @@ interface SenderBuffer { arrayColumn(name: string, value: unknown[]): SenderBuffer; /** - * Writes a 64-bit signed integer into the buffer.
+ * Writes a 64-bit signed integer into the buffer. * Use it to insert into LONG, INT, SHORT and BYTE columns. - * - * @param {string} name - Column name. - * @param {number} value - Column value, accepts only number values. - * @return {Sender} Returns with a reference to this sender. + * @param name - Column name. + * @param value - Column value, accepts only number values. + * @returns Returns with a reference to this buffer. * @throws Error if the value is not an integer */ intColumn(name: string, value: number): SenderBuffer; /** - * Writes a timestamp column with its value into the buffer.
+ * Writes a timestamp column with its value into the buffer. * Use it to insert into TIMESTAMP columns. - * - * @param {string} name - Column name. - * @param {number | bigint} value - Epoch timestamp, accepts numbers or BigInts. - * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'. - * @return {Sender} Returns with a reference to this sender. + * @param name - Column name. + * @param value - Epoch timestamp, accepts numbers or BigInts. + * @param unit - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. + * @returns Returns with a reference to this buffer. */ timestampColumn( name: string, @@ -161,21 +155,21 @@ interface SenderBuffer { /** * Closes the row after writing the designated timestamp into the buffer. - * - * @param {number | bigint} timestamp - Designated epoch timestamp, accepts numbers or BigInts. - * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'. + * @param timestamp - Designated epoch timestamp, accepts numbers or BigInts. + * @param unit - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. */ at(timestamp: number | bigint, unit: TimestampUnit): void; /** - * Closes the row without writing designated timestamp into the buffer.
+ * Closes the row without writing designated timestamp into the buffer. * Designated timestamp will be populated by the server on this record. */ atNow(): void; /** - * Returns the current position of the buffer.
+ * Returns the current position of the buffer. * New data will be written into the buffer starting from this position. + * @returns The current write position in the buffer */ currentPosition(): number; } diff --git a/src/index.ts b/src/index.ts index 3f335c4..1ac4d17 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,16 @@ /** * A Node.js client for QuestDB. - * - * @module @questdb/nodejs-client + * @packageDocumentation */ -import { Sender } from "./sender"; -export { Sender }; +export { Sender } from "./sender"; +export type { SenderOptions, ExtraOptions } from "./options"; +export type { TimestampUnit } from "./utils"; +export type { SenderBuffer } from "./buffer"; +export { SenderBufferV1 } from "./buffer/bufferv1"; +export { SenderBufferV2 } from "./buffer/bufferv2"; +export type { SenderTransport } from "./transport"; +export { TcpTransport } from "./transport/tcp"; +export { HttpTransport } from "./transport/http/stdlib"; +export { UndiciTransport } from "./transport/http/undici"; +export type { Logger } from "./logging"; diff --git a/src/logging.ts b/src/logging.ts index e9762fc..85818dd 100644 --- a/src/logging.ts +++ b/src/logging.ts @@ -32,7 +32,7 @@ type Logger = ( function log( level: "error" | "warn" | "info" | "debug", message: string | Error, -) { +): void { const logLevel = LOG_LEVELS[level]; if (!logLevel) { throw new Error(`Invalid log level: '${level}'`); diff --git a/src/options.ts b/src/options.ts index 8d60555..5c3f589 100644 --- a/src/options.ts +++ b/src/options.ts @@ -40,8 +40,8 @@ type DeprecatedOptions = { bufferSize?: number; }; -/** @classdesc - * Sender configuration options.
+/** + * {@link Sender} configuration options. *
* Properties of the object are initialized through a configuration string.
* The configuration string has the following format: <protocol>::<key>=<value><key>=<value>...;
@@ -194,9 +194,9 @@ class SenderOptions { * * @param {string} configurationString - Configuration string.
* @param {object} extraOptions - Optional extra configuration.
- * - 'log' is a logging function used by the Sender.
+ * - 'log' is a logging function used by the {@link Sender}. * Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
- * - 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
+ * - 'agent' is a custom http/https agent used by the {@link Sender} when http/https transport is used. * Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent. */ constructor(configurationString: string, extraOptions?: ExtraOptions) { @@ -264,8 +264,7 @@ class SenderOptions { options.protocol_version = PROTOCOL_VERSION_V1; } else { throw new Error( - "Unsupported protocol versions received from server: " + - supportedVersions, + `Unsupported protocol versions received from server: ${supportedVersions}`, ); } return options; @@ -309,9 +308,9 @@ class SenderOptions { * * @param {string} configurationString - Configuration string.
* @param {object} extraOptions - Optional extra configuration.
- * - 'log' is a logging function used by the Sender.
+ * - 'log' is a logging function used by the {@link Sender}. * Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
- * - 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
+ * - 'agent' is a custom http/https agent used by the {@link Sender} when http/https transport is used. * Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent. * * @return {SenderOptions} A Sender configuration object initialized from the provided configuration string. @@ -329,9 +328,9 @@ class SenderOptions { * Creates a Sender options object by parsing the configuration string set in the QDB_CLIENT_CONF environment variable. * * @param {object} extraOptions - Optional extra configuration.
- * - 'log' is a logging function used by the Sender.
+ * - 'log' is a logging function used by the {@link Sender}. * Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
- * - 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
+ * - 'agent' is a custom http/https agent used by the {@link Sender} when http/https transport is used. * Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent. * * @return {SenderOptions} A Sender configuration object initialized from the QDB_CLIENT_CONF environment variable. @@ -556,8 +555,7 @@ function parseTlsOptions(options: SenderOptions) { if (options.tls_roots || options.tls_roots_password) { throw new Error( - "'tls_roots' and 'tls_roots_password' options are not supported, please, " + - "use the 'tls_ca' option or the NODE_EXTRA_CA_CERTS environment variable instead", + `'tls_roots' and 'tls_roots_password' options are not supported, please, use the 'tls_ca' option or the NODE_EXTRA_CA_CERTS environment variable instead`, ); } } diff --git a/src/sender.ts b/src/sender.ts index 58db7b4..275a018 100644 --- a/src/sender.ts +++ b/src/sender.ts @@ -7,7 +7,7 @@ import { isBoolean, isInteger, TimestampUnit } from "./utils"; const DEFAULT_AUTO_FLUSH_INTERVAL = 1000; // 1 sec -/** @classdesc +/** * The QuestDB client's API provides methods to connect to the database, ingest data, and close the connection.
* The client supports multiple transport protocols. *

@@ -52,7 +52,7 @@ const DEFAULT_AUTO_FLUSH_INTERVAL = 1000; // 1 sec * If the Sender is created via its constructor, at least the SenderOptions configuration object should be * initialized from a configuration string to make sure that the parameters are validated.
* Detailed description of the Sender's configuration options can be found in - * the SenderOptions documentation. + * the {@link SenderOptions} documentation. *

*

* Transport Configuration Examples: @@ -124,9 +124,9 @@ class Sender { * * @param {string} configurationString - Configuration string.
* @param {object} extraOptions - Optional extra configuration.
- * - 'log' is a logging function used by the Sender.
+ * - 'log' is a logging function used by the {@link Sender}. * Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
- * - 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
+ * - 'agent' is a custom http/https agent used by the {@link Sender} when http/https transport is used. * Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent. * * @return {Sender} A Sender object initialized from the provided configuration string. @@ -144,9 +144,9 @@ class Sender { * Creates a Sender object by parsing the configuration string set in the QDB_CLIENT_CONF environment variable. * * @param {object} extraOptions - Optional extra configuration.
- * - 'log' is a logging function used by the Sender.
+ * - 'log' is a logging function used by the {@link Sender}. * Prototype: (level: 'error'|'warn'|'info'|'debug', message: string) => void.
- * - 'agent' is a custom http/https agent used by the Sender when http/https transport is used.
+ * - 'agent' is a custom http/https agent used by the {@link Sender} when http/https transport is used. * Depends on which transport implementation and protocol used, one of the followings expected: undici.Agent, http.Agent or https.Agent. * * @return {Sender} A Sender object initialized from the QDB_CLIENT_CONF environment variable. @@ -197,13 +197,14 @@ class Sender { this.resetAutoFlush(); await this.transport.send(dataToSend); + return true; } /** * Closes the connection to the database.
* Data sitting in the Sender's buffer will be lost unless flush() is called before close(). */ - async close() { + async close(): Promise { const pos = this.buffer.currentPosition(); if (pos > 0) { this.log( @@ -331,7 +332,10 @@ class Sender { * @param {number | bigint} timestamp - Designated epoch timestamp, accepts numbers or BigInts. * @param {string} [unit=us] - Timestamp unit. Supported values: 'ns' - nanoseconds, 'us' - microseconds, 'ms' - milliseconds. Defaults to 'us'. */ - async at(timestamp: number | bigint, unit: TimestampUnit = "us") { + async at( + timestamp: number | bigint, + unit: TimestampUnit = "us", + ): Promise { this.buffer.at(timestamp, unit); this.pendingRowCount++; this.log("debug", `Pending row count: ${this.pendingRowCount}`); @@ -342,7 +346,7 @@ class Sender { * Closes the row without writing designated timestamp into the buffer of the sender.
* Designated timestamp will be populated by the server on this record. */ - async atNow() { + async atNow(): Promise { this.buffer.atNow(); this.pendingRowCount++; this.log("debug", `Pending row count: ${this.pendingRowCount}`); @@ -355,7 +359,7 @@ class Sender { this.log("debug", `Pending row count: ${this.pendingRowCount}`); } - private async tryFlush() { + private async tryFlush(): Promise { if ( this.autoFlush && this.pendingRowCount > 0 && diff --git a/src/transport/http/stdlib.ts b/src/transport/http/stdlib.ts index af840e6..be4e27e 100644 --- a/src/transport/http/stdlib.ts +++ b/src/transport/http/stdlib.ts @@ -221,7 +221,7 @@ class HttpTransport extends HttpTransportBase { * @param {number} statusCode - HTTP status code to check * @returns True if the status code indicates a retryable error */ -function isRetryable(statusCode: number) { +function isRetryable(statusCode: number): boolean { return RETRIABLE_STATUS_CODES.includes(statusCode); } diff --git a/src/transport/http/undici.ts b/src/transport/http/undici.ts index a24dadb..676abfe 100644 --- a/src/transport/http/undici.ts +++ b/src/transport/http/undici.ts @@ -110,7 +110,7 @@ class UndiciTransport extends HttpTransportBase { const controller = new AbortController(); const { signal } = controller; - setTimeout(() => controller.abort(), this.retryTimeout); + const timeoutId = setTimeout(() => controller.abort(), this.retryTimeout); let responseData: Dispatcher.ResponseData; try { @@ -134,6 +134,8 @@ class UndiciTransport extends HttpTransportBase { } else { throw err; } + } finally { + clearTimeout(timeoutId); } const { statusCode } = responseData; diff --git a/src/transport/index.ts b/src/transport/index.ts index e81a7db..3b0d65d 100644 --- a/src/transport/index.ts +++ b/src/transport/index.ts @@ -12,7 +12,7 @@ import { HttpTransport } from "./http/stdlib"; */ interface SenderTransport { /** - * Establishes a connection to the database server.
+ * Establishes a connection to the database server. * Should not be called on HTTP transports. * @returns Promise resolving to true if connection is successful */ @@ -20,13 +20,13 @@ interface SenderTransport { /** * Sends the data to the database server. - * @param {Buffer} data - Buffer containing the data to send + * @param data - Buffer containing the data to send * @returns Promise resolving to true if data was sent successfully */ send(data: Buffer): Promise; /** - * Closes the connection to the database server.
+ * Closes the connection to the database server. * Should not be called on HTTP transports. * @returns Promise that resolves when the connection is closed */ @@ -41,7 +41,7 @@ interface SenderTransport { /** * Factory function to create appropriate transport instance based on configuration. - * @param {SenderOptions} options - Sender configuration options including protocol and connection details + * @param options - Sender configuration options including protocol and connection details * @returns Transport instance appropriate for the specified protocol * @throws Error if protocol or host options are missing or invalid */ diff --git a/src/transport/tcp.ts b/src/transport/tcp.ts index 57b5026..efc76fa 100644 --- a/src/transport/tcp.ts +++ b/src/transport/tcp.ts @@ -20,6 +20,9 @@ const PUBLIC_KEY = { y: "__ptaol41JWSpTTL525yVEfzmY8A6Vi_QrW1FjKcHMg", }; +// New Line character +const NEWLINE = 10; + /** * TCP transport implementation.
* Supports both plain TCP or secure TLS-encrypted connections with configurable JWK token authentication. @@ -131,9 +134,15 @@ class TcpTransport implements SenderTransport { "info", `Authenticating with ${connOptions.host}:${connOptions.port}`, ); - this.socket.write(`${this.jwk.kid}\n`, (err) => - err ? reject(err) : () => {}, - ); + this.socket.write(`${this.jwk.kid}\n`, (err) => { + if (err) { + this.log( + "error", + `Failed to send authentication: ${err.message}`, + ); + reject(err); + } + }); } else { authenticated = true; if (!this.secure || !this.tlsVerify) { @@ -149,6 +158,12 @@ class TcpTransport implements SenderTransport { err.code !== "SELF_SIGNED_CERT_IN_CHAIN" ) { reject(err); + } else { + // Warn about accepting self-signed certificate + this.log( + "warn", + "Accepting self-signed certificate. This is insecure and should only be used in development environments.", + ); } }); }); @@ -183,7 +198,7 @@ class TcpTransport implements SenderTransport { const address = this.socket.remoteAddress; const port = this.socket.remotePort; this.socket.destroy(); - this.socket = null; + this.socket = undefined; this.log("info", `Connection to ${address}:${port} is closed`); } } @@ -204,7 +219,7 @@ class TcpTransport implements SenderTransport { */ private async authenticate(challenge: Buffer): Promise { // Check for trailing \n which ends the challenge - if (challenge.subarray(-1).readInt8() === 10) { + if (challenge.subarray(-1).readInt8() === NEWLINE) { const keyObject = crypto.createPrivateKey({ key: this.jwk, format: "jwk", @@ -238,15 +253,14 @@ class TcpTransport implements SenderTransport { * @param {SenderOptions} options - Sender options that may contain authentication details * @throws Error if username or token is missing when authentication is intended */ -function constructAuth(options: SenderOptions) { +function constructAuth(options: SenderOptions): void { if (!options.username && !options.token && !options.password) { // no intention to authenticate return; } if (!options.username || !options.token) { throw new Error( - "TCP transport requires a username and a private key for authentication, " + - "please, specify the 'username' and 'token' config options", + `TCP transport requires a username and a private key for authentication, please, specify the 'username' and 'token' config options`, ); } @@ -263,30 +277,26 @@ function constructAuth(options: SenderOptions) { * @returns JWK object with key ID, private key, and public key coordinates * @throws Error if required authentication properties are missing or invalid */ -function constructJwk(options: SenderOptions) { +function constructJwk(options: SenderOptions): Record { if (options.auth) { if (!options.auth.keyId) { throw new Error( - "Missing username, please, specify the 'keyId' property of the 'auth' config option. " + - "For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})", + `Missing username, please, specify the 'keyId' property of the 'auth' config option. For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})`, ); } if (typeof options.auth.keyId !== "string") { throw new Error( - "Please, specify the 'keyId' property of the 'auth' config option as a string. " + - "For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})", + `Please, specify the 'keyId' property of the 'auth' config option as a string. For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})`, ); } if (!options.auth.token) { throw new Error( - "Missing private key, please, specify the 'token' property of the 'auth' config option. " + - "For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})", + `Missing private key, please, specify the 'token' property of the 'auth' config option. For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})`, ); } if (typeof options.auth.token !== "string") { throw new Error( - "Please, specify the 'token' property of the 'auth' config option as a string. " + - "For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})", + `Please, specify the 'token' property of the 'auth' config option as a string. For example: new Sender({protocol: 'tcp', host: 'host', auth: {keyId: 'username', token: 'private key'}})`, ); } diff --git a/src/utils.ts b/src/utils.ts index d7f580c..968734e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -39,7 +39,7 @@ function isInteger(value: unknown, lowerBound: number): value is number { * @returns The timestamp converted to microseconds * @throws Error if the timestamp unit is unknown */ -function timestampToMicros(timestamp: bigint, unit: TimestampUnit) { +function timestampToMicros(timestamp: bigint, unit: TimestampUnit): bigint { switch (unit) { case "ns": return timestamp / 1000n; @@ -59,7 +59,7 @@ function timestampToMicros(timestamp: bigint, unit: TimestampUnit) { * @returns The timestamp converted to nanoseconds * @throws Error if the timestamp unit is unknown */ -function timestampToNanos(timestamp: bigint, unit: TimestampUnit) { +function timestampToNanos(timestamp: bigint, unit: TimestampUnit): bigint { switch (unit) { case "ns": return timestamp; @@ -78,7 +78,7 @@ function timestampToNanos(timestamp: bigint, unit: TimestampUnit) { * @returns Array of dimension sizes at each nesting level * @throws Error if any dimension has zero length */ -function getDimensions(data: unknown) { +function getDimensions(data: unknown): number[] { const dimensions: number[] = []; while (Array.isArray(data)) { dimensions.push(data.length); diff --git a/src/validation.ts b/src/validation.ts index e358d35..85239ae 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -5,7 +5,7 @@ * @param {number} maxNameLength - The maximum length of table names. * @throws Error if table name is invalid. */ -function validateTableName(name: string, maxNameLength: number) { +function validateTableName(name: string, maxNameLength: number): void { const len = name.length; if (len > maxNameLength) { throw new Error(`Table name is too long, max length is ${maxNameLength}`); @@ -71,7 +71,7 @@ function validateTableName(name: string, maxNameLength: number) { * @param {number} maxNameLength - The maximum length of column names. * @throws Error if column name is invalid. */ -function validateColumnName(name: string, maxNameLength: number) { +function validateColumnName(name: string, maxNameLength: number): void { const len = name.length; if (len > maxNameLength) { throw new Error(`Column name is too long, max length is ${maxNameLength}`); diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..d76ef0d --- /dev/null +++ b/typedoc.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["./src/index.ts"], + "out": "docs", + "name": "QuestDB Node.js Client", + "readme": "./README.md", + "tsconfig": "./tsconfig.json", + "exclude": ["**/test/**/*", "**/examples/**/*", "**/node_modules/**/*"], + "excludePrivate": true, + "excludeProtected": false, + "excludeInternal": true, + "includeVersion": true, + "disableSources": false, + "searchInComments": true, + "navigationLinks": { + "GitHub": "https://github.com/questdb/nodejs-questdb-client", + "QuestDB": "https://questdb.io" + }, + "categorizeByGroup": true, + "sort": ["source-order"], + "visibilityFilters": { + "protected": true, + "private": false, + "inherited": true, + "external": false + } +} \ No newline at end of file