@influxdata/influxdb3-client-browser
Version:
InfluxDB 3 client for browser
1 lines • 378 kB
Source Map (JSON)
{"version":3,"sources":["../src/errors.ts","../src/results/chunkCombiner.ts","../src/options.ts","../src/util/logger.ts","../src/util/escape.ts","../src/util/time.ts","../src/util/common.ts","../src/util/generics.ts","../src/PointValues.ts","../src/Point.ts","../src/impl/node/NodeHttpTransport.ts","../src/impl/completeCommunicationObserver.ts","../src/impl/version.ts","../src/impl/node/rpc.ts","../src/util/fixUrl.ts","../src/impl/node/index.ts","../src/impl/WriteApiImpl.ts","../src/impl/QueryApiImpl.ts","../src/generated/flight/Flight.ts","../../../node_modules/@protobuf-ts/runtime/build/es2015/json-typings.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/base64.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/binary-format-contract.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/goog-varint.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/pb-long.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/binary-reader.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/assert.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/binary-writer.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/json-format-contract.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/message-type-contract.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/lower-camel-case.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-info.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/oneof.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-type-check.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-long-convert.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-json-reader.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-json-writer.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-scalar-default.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-binary-reader.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-binary-writer.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-create.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-merge-partial.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/reflection-equals.js","../../../node_modules/@protobuf-ts/runtime/build/es2015/message-type.js","../src/generated/flight/google/protobuf/timestamp.ts","../src/generated/flight/Flight.client.ts","../src/util/sql.ts","../src/util/TypeCasting.ts","../src/InfluxDBClient.ts"],"sourcesContent":["import {Headers} from './results'\n\n/** IllegalArgumentError is thrown when illegal argument is supplied. */\nexport class IllegalArgumentError extends Error {\n /* istanbul ignore next */\n constructor(message: string) {\n super(message)\n this.name = 'IllegalArgumentError'\n Object.setPrototypeOf(this, IllegalArgumentError.prototype)\n }\n}\n\n/**\n * A general HTTP error.\n */\nexport class HttpError extends Error {\n /** application error code, when available */\n public code: string | undefined\n /** json error response */\n public json: any\n\n /* istanbul ignore next because of super() not being covered*/\n constructor(\n readonly statusCode: number,\n readonly statusMessage: string | undefined,\n readonly body?: string,\n readonly contentType?: string | undefined | null,\n readonly headers?: Headers | null,\n message?: string\n ) {\n super()\n Object.setPrototypeOf(this, HttpError.prototype)\n if (message) {\n this.message = message\n } else if (body) {\n // Edge may not set Content-Type header\n if (contentType?.startsWith('application/json') || !contentType) {\n try {\n this.json = JSON.parse(body)\n this.message = this.json.message\n this.code = this.json.code\n if (!this.message) {\n interface EdgeBody {\n error?: string\n data?: {\n error_message?: string\n }\n }\n const eb: EdgeBody = this.json as EdgeBody\n if (eb.data?.error_message) {\n this.message = eb.data.error_message\n } else if (eb.error) {\n this.message = eb.error\n }\n }\n } catch (e) {\n // silently ignore, body string is still available\n }\n }\n }\n if (!this.message) {\n this.message = `${statusCode} ${statusMessage} : ${body}`\n }\n this.name = 'HttpError'\n }\n}\n\n/** RequestTimedOutError indicates request timeout in the communication with the server */\nexport class RequestTimedOutError extends Error {\n /* istanbul ignore next because of super() not being covered */\n constructor() {\n super()\n Object.setPrototypeOf(this, RequestTimedOutError.prototype)\n this.name = 'RequestTimedOutError'\n this.message = 'Request timed out'\n }\n}\n\n/** AbortError indicates that the communication with the server was aborted */\nexport class AbortError extends Error {\n /* istanbul ignore next because of super() not being covered */\n constructor() {\n super()\n this.name = 'AbortError'\n Object.setPrototypeOf(this, AbortError.prototype)\n this.message = 'Response aborted'\n }\n}\n","/**\n * ChunkCombiner is a simplified platform-neutral manipulation of Uint8arrays\n * that allows to process text data on the fly. The implementation can be optimized\n * for the target platform (node vs browser).\n */\nexport interface ChunkCombiner {\n /**\n * Concatenates first and second chunk.\n * @param first - first chunk\n * @param second - second chunk\n * @returns first + second\n */\n concat(first: Uint8Array, second: Uint8Array): Uint8Array\n\n /**\n * Converts chunk into a string.\n * @param chunk - chunk\n * @param start - start index\n * @param end - end index\n * @returns string representation of chunk slice\n */\n toUtf8String(chunk: Uint8Array, start: number, end: number): string\n\n /**\n * Creates a new chunk from the supplied chunk.\n * @param chunk - chunk to copy\n * @param start - start index\n * @param end - end index\n * @returns a copy of a chunk slice\n */\n copy(chunk: Uint8Array, start: number, end: number): Uint8Array\n}\n\n// TextDecoder is available since node v8.3.0 and in all modern browsers\ndeclare class TextDecoder {\n constructor(encoding: string)\n decode(chunk: Uint8Array): string\n}\n\n/**\n * Creates a chunk combiner instance that uses UTF-8\n * TextDecoder to decode Uint8Arrays into strings.\n */\nexport function createTextDecoderCombiner(): ChunkCombiner {\n const decoder = new TextDecoder('utf-8')\n return {\n concat(first: Uint8Array, second: Uint8Array): Uint8Array {\n const retVal = new Uint8Array(first.length + second.length)\n retVal.set(first)\n retVal.set(second, first.length)\n return retVal\n },\n copy(chunk: Uint8Array, start: number, end: number): Uint8Array {\n const retVal = new Uint8Array(end - start)\n retVal.set(chunk.subarray(start, end))\n return retVal\n },\n toUtf8String(chunk: Uint8Array, start: number, end: number): string {\n return decoder.decode(chunk.subarray(start, end))\n },\n }\n}\n","import {Transport} from './transport'\nimport {QParamType} from './QueryApi'\n\n/**\n * Option for the communication with InfluxDB server.\n */\nexport interface ConnectionOptions {\n /** base host URL */\n host: string\n /** authentication token */\n token?: string\n /** token authentication scheme. Not set for Cloud access, set to 'Bearer' for Edge. */\n authScheme?: string\n /**\n * socket timeout. 10000 milliseconds by default in node.js. Not applicable in browser (option is ignored).\n * @defaultValue 10000\n */\n timeout?: number\n /**\n * stream timeout for query (grpc timeout). The gRPC doesn't apply the socket timeout to operations as is defined above. To successfully close a call to the gRPC endpoint, the queryTimeout must be specified. Without this timeout, a gRPC call might end up in an infinite wait state.\n * @defaultValue 60000\n */\n queryTimeout?: number\n /**\n * default database for write query if not present as argument.\n */\n database?: string\n /**\n * TransportOptions supply extra options for the transport layer, they differ between node.js and browser/deno.\n * Node.js transport accepts options specified in {@link https://nodejs.org/api/http.html#http_http_request_options_callback | http.request } or\n * {@link https://nodejs.org/api/https.html#https_https_request_options_callback | https.request }. For example, an `agent` property can be set to\n * {@link https://www.npmjs.com/package/proxy-http-agent | setup HTTP/HTTPS proxy }, {@link https://nodejs.org/api/tls.html#tls_tls_connect_options_callback | rejectUnauthorized }\n * property can disable TLS server certificate verification. Additionally,\n * {@link https://github.com/follow-redirects/follow-redirects | follow-redirects } property can be also specified\n * in order to follow redirects in node.js.\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/fetch | fetch } is used under the hood in browser/deno.\n * For example,\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/fetch | redirect } property can be set to 'error' to abort request if a redirect occurs.\n */\n transportOptions?: {[key: string]: any}\n /**\n * Default HTTP headers to send with every request.\n */\n headers?: Record<string, string>\n /**\n * Full HTTP web proxy URL including schema, for example http://your-proxy:8080.\n */\n proxyUrl?: string\n\n /**\n * Grpc options to be passed when instantiating query transport. See supported channel options in @grpc/grpc-js/README.md.\n */\n grpcOptions?: Record<string, any>\n}\n\n/** default connection options */\nexport const DEFAULT_ConnectionOptions: Partial<ConnectionOptions> = {\n timeout: 10000,\n queryTimeout: 60000,\n}\n\n/**\n * Options used by {@link InfluxDBClient.default.write} .\n *\n * @example WriteOptions in write call\n * ```typescript\n * client\n * .write(point, DATABASE, 'cpu', {\n * headers: {\n * 'channel-lane': 'reserved',\n * 'notify-central': '30m',\n * },\n * precision: 'ns',\n * gzipThreshold: 1000,\n * noSync: false,\n * })\n * ```\n */\nexport interface WriteOptions {\n /** Precision to use in writes for timestamp. default ns */\n precision?: WritePrecision\n /** HTTP headers that will be sent with every write request */\n //headers?: {[key: string]: string}\n headers?: Record<string, string>\n /** When specified, write bodies larger than the threshold are gzipped */\n gzipThreshold?: number\n /**\n * Instructs the server whether to wait with the response until WAL persistence completes.\n * noSync=true means faster write but without the confirmation that the data was persisted.\n *\n * Note: This option is supported by InfluxDB 3 Core and Enterprise servers only.\n * For other InfluxDB 3 server types (InfluxDB Clustered, InfluxDB Clould Serverless/Dedicated)\n * the write operation will fail with an error.\n *\n * Default value: false.\n */\n noSync?: boolean\n /** default tags\n *\n * @example Default tags using client config\n * ```typescript\n * const client = new InfluxDBClient({\n * host: 'https://eu-west-1-1.aws.cloud2.influxdata.com',\n * writeOptions: {\n * defaultTags: {\n * device: 'nrdc-th-52-fd889e03',\n * },\n * },\n * })\n *\n * const p = Point.measurement('measurement').setField('num', 3)\n *\n * // this will write point with device=device-a tag\n * await client.write(p, 'my-db')\n * ```\n *\n * @example Default tags using writeOptions argument\n * ```typescript\n * const client = new InfluxDBClient({\n * host: 'https://eu-west-1-1.aws.cloud2.influxdata.com',\n * })\n *\n * const defaultTags = {\n * device: 'rpi5_0_0599e8d7',\n * }\n *\n * const p = Point.measurement('measurement').setField('num', 3)\n *\n * // this will write point with device=device-a tag\n * await client.write(p, 'my-db', undefined, {defaultTags})\n * ```\n */\n defaultTags?: {[key: string]: string}\n}\n\n/** default writeOptions */\nexport const DEFAULT_WriteOptions: WriteOptions = {\n precision: 'ns',\n gzipThreshold: 1000,\n noSync: false,\n}\n\nexport type QueryType = 'sql' | 'influxql'\n\n/**\n * Options used by {@link InfluxDBClient.default.query} and by {@link InfluxDBClient.default.queryPoints}.\n *\n * @example QueryOptions in queryCall\n * ```typescript\n * const data = client.query('SELECT * FROM drive', 'ev_onboard_45ae770c', {\n * type: 'sql',\n * headers: {\n * 'one-off': 'totl', // one-off query header\n * 'change-on': 'shift1', // over-write universal value\n * },\n * params: {\n * point: 'a7',\n * action: 'reverse',\n * },\n * })\n * ```\n */\nexport interface QueryOptions {\n /** Type of query being sent, e.g. 'sql' or 'influxql'.*/\n type: QueryType\n /** Custom headers to add to the request.*/\n headers?: Record<string, string>\n /** Parameters to accompany a query using them.*/\n params?: Record<string, QParamType>\n /** GRPC specific Parameters to be set when instantiating a client\n * See supported channel options in @grpc/grpc-js/README.md. **/\n grpcOptions?: Record<string, any>\n}\n\n/** Default QueryOptions */\nexport const DEFAULT_QueryOptions: QueryOptions = {\n type: 'sql',\n}\n\n/**\n * Options used by {@link InfluxDBClient} .\n */\nexport interface ClientOptions extends ConnectionOptions {\n /** supplies query options to be use with each and every query.*/\n queryOptions?: Partial<QueryOptions>\n /** supplies and overrides default writing options.*/\n writeOptions?: Partial<WriteOptions>\n /** specifies custom transport */\n transport?: Transport\n}\n\n/**\n * Timestamp precision used in write operations.\n * See {@link https://docs.influxdata.com/influxdb/latest/api/#operation/PostWrite }\n */\nexport type WritePrecision = 'ns' | 'us' | 'ms' | 's'\n\n/**\n * Parses connection string into `ClientOptions`.\n * @param connectionString - connection string\n */\nexport function fromConnectionString(connectionString: string): ClientOptions {\n if (!connectionString) {\n throw Error('Connection string not set!')\n }\n const url = new URL(connectionString.trim(), 'http://localhost') // artificial base is ignored when url is absolute\n const options: ClientOptions = {\n host:\n connectionString.indexOf('://') > 0\n ? url.origin + url.pathname\n : url.pathname,\n }\n if (url.searchParams.has('token')) {\n options.token = url.searchParams.get('token') as string\n }\n if (url.searchParams.has('authScheme')) {\n options.authScheme = url.searchParams.get('authScheme') as string\n }\n if (url.searchParams.has('database')) {\n options.database = url.searchParams.get('database') as string\n }\n if (url.searchParams.has('timeout')) {\n options.timeout = parseInt(url.searchParams.get('timeout') as string)\n }\n if (url.searchParams.has('precision')) {\n if (!options.writeOptions) options.writeOptions = {} as WriteOptions\n options.writeOptions.precision = parsePrecision(\n url.searchParams.get('precision') as string\n )\n }\n if (url.searchParams.has('gzipThreshold')) {\n if (!options.writeOptions) options.writeOptions = {} as WriteOptions\n options.writeOptions.gzipThreshold = parseInt(\n url.searchParams.get('gzipThreshold') as string\n )\n }\n if (url.searchParams.has('writeNoSync')) {\n if (!options.writeOptions) options.writeOptions = {} as WriteOptions\n options.writeOptions.noSync = parseBoolean(\n url.searchParams.get('writeNoSync') as string\n )\n }\n\n return options\n}\n\n/**\n * Creates `ClientOptions` from environment variables.\n */\nexport function fromEnv(): ClientOptions {\n if (!process.env.INFLUX_HOST) {\n throw Error('INFLUX_HOST variable not set!')\n }\n if (!process.env.INFLUX_TOKEN) {\n throw Error('INFLUX_TOKEN variable not set!')\n }\n const options: ClientOptions = {\n host: process.env.INFLUX_HOST.trim(),\n }\n if (process.env.INFLUX_TOKEN) {\n options.token = process.env.INFLUX_TOKEN.trim()\n }\n if (process.env.INFLUX_AUTH_SCHEME) {\n options.authScheme = process.env.INFLUX_AUTH_SCHEME.trim()\n }\n if (process.env.INFLUX_DATABASE) {\n options.database = process.env.INFLUX_DATABASE.trim()\n }\n if (process.env.INFLUX_TIMEOUT) {\n options.timeout = parseInt(process.env.INFLUX_TIMEOUT.trim())\n }\n if (process.env.INFLUX_PRECISION) {\n if (!options.writeOptions) options.writeOptions = {} as WriteOptions\n options.writeOptions.precision = parsePrecision(\n process.env.INFLUX_PRECISION as string\n )\n }\n if (process.env.INFLUX_GZIP_THRESHOLD) {\n if (!options.writeOptions) options.writeOptions = {} as WriteOptions\n options.writeOptions.gzipThreshold = parseInt(\n process.env.INFLUX_GZIP_THRESHOLD\n )\n }\n if (process.env.INFLUX_WRITE_NO_SYNC) {\n if (!options.writeOptions) options.writeOptions = {} as WriteOptions\n options.writeOptions.noSync = parseBoolean(process.env.INFLUX_WRITE_NO_SYNC)\n }\n if (process.env.INFLUX_GRPC_OPTIONS) {\n const optionSets = process.env.INFLUX_GRPC_OPTIONS.split(',')\n if (!options.grpcOptions) options.grpcOptions = {} as Record<string, any>\n for (const optSet of optionSets) {\n const kvPair = optSet.split('=')\n // ignore malformed values\n if (kvPair.length != 2) {\n continue\n }\n let value: any = parseInt(kvPair[1])\n if (Number.isNaN(value)) {\n value = parseFloat(kvPair[1])\n if (Number.isNaN(value)) {\n value = kvPair[1]\n }\n }\n options.grpcOptions[kvPair[0]] = value\n }\n }\n\n return options\n}\n\nfunction parseBoolean(value: string): boolean {\n return ['true', '1', 't', 'y', 'yes'].includes(value.trim().toLowerCase())\n}\n\nexport function precisionToV2ApiString(precision: WritePrecision): string {\n switch (precision) {\n case 'ns':\n case 'us':\n case 'ms':\n case 's':\n return precision as string\n default:\n throw Error(`Unsupported precision '${precision}'`)\n }\n}\n\nexport function precisionToV3ApiString(precision: WritePrecision): string {\n switch (precision) {\n case 'ns':\n return 'nanosecond'\n case 'us':\n return 'microsecond'\n case 'ms':\n return 'millisecond'\n case 's':\n return 'second'\n default:\n throw Error(`Unsupported precision '${precision}'`)\n }\n}\n\nexport function parsePrecision(value: string): WritePrecision {\n switch (value.trim().toLowerCase()) {\n case 'ns':\n case 'nanosecond':\n return 'ns'\n case 'us':\n case 'microsecond':\n return 'us'\n case 'ms':\n case 'millisecond':\n return 'ms'\n case 's':\n case 'second':\n return 's'\n default:\n throw Error(`Unsupported precision '${value}'`)\n }\n}\n","/**\n * Logging interface.\n */\nexport interface Logger {\n error(message: string, err?: any): void\n warn(message: string, err?: any): void\n}\n\n/**\n * Logger that logs to console.out\n */\nexport const consoleLogger: Logger = {\n error(message, error) {\n // eslint-disable-next-line no-console\n console.error(`ERROR: ${message}`, error ? error : '')\n },\n warn(message, error) {\n // eslint-disable-next-line no-console\n console.warn(`WARN: ${message}`, error ? error : '')\n },\n}\nlet provider: Logger = consoleLogger\n\nexport const Log: Logger = {\n error(message, error) {\n provider.error(message, error)\n },\n warn(message, error) {\n provider.warn(message, error)\n },\n}\n\n/**\n * Sets custom logger.\n * @param logger - logger to use\n * @returns previous logger\n */\nexport function setLogger(logger: Logger): Logger {\n const previous = provider\n provider = logger\n return previous\n}\n","function createEscaper(\n characters: string,\n replacements: string[]\n): (value: string) => string {\n return function (value: string): string {\n let retVal = ''\n let from = 0\n let i = 0\n while (i < value.length) {\n const found = characters.indexOf(value[i])\n if (found >= 0) {\n retVal += value.substring(from, i)\n retVal += replacements[found]\n from = i + 1\n }\n i++\n }\n if (from == 0) {\n return value\n } else if (from < value.length) {\n retVal += value.substring(from, value.length)\n }\n return retVal\n }\n}\nfunction createQuotedEscaper(\n characters: string,\n replacements: string[]\n): (value: string) => string {\n const escaper = createEscaper(characters, replacements)\n return (value: string): string => `\"${escaper(value)}\"`\n}\n\n/**\n * Provides functions escape specific parts in InfluxDB line protocol.\n */\nexport const escape = {\n /**\n * Measurement escapes measurement names.\n */\n measurement: createEscaper(', \\n\\r\\t', ['\\\\,', '\\\\ ', '\\\\n', '\\\\r', '\\\\t']),\n /**\n * Quoted escapes quoted values, such as database names.\n */\n quoted: createQuotedEscaper('\"\\\\', ['\\\\\"', '\\\\\\\\']),\n\n /**\n * TagEscaper escapes tag keys, tag values, and field keys.\n */\n tag: createEscaper(', =\\n\\r\\t', ['\\\\,', '\\\\ ', '\\\\=', '\\\\n', '\\\\r', '\\\\t']),\n}\n","import {WritePrecision} from '../options'\n\ndeclare let process: any\nconst zeroPadding = '000000000'\nlet useHrTime = false\n\nexport function useProcessHrtime(use: boolean): boolean {\n /* istanbul ignore else */\n if (!process.env.BUILD_BROWSER) {\n return (useHrTime = use && process && typeof process.hrtime === 'function')\n } else {\n return false\n }\n}\nuseProcessHrtime(true) // preffer node\n\nlet startHrMillis: number | undefined = undefined\nlet startHrTime: [number, number] | undefined = undefined\nlet lastMillis = Date.now()\nlet stepsInMillis = 0\nfunction nanos(): string {\n if (!process.env.BUILD_BROWSER && useHrTime) {\n const hrTime = process.hrtime() as [number, number]\n let millis = Date.now()\n if (!startHrTime) {\n startHrTime = hrTime\n startHrMillis = millis\n } else {\n hrTime[0] = hrTime[0] - startHrTime[0]\n hrTime[1] = hrTime[1] - startHrTime[1]\n // istanbul ignore next \"cannot mock system clock, manually reviewed\"\n if (hrTime[1] < 0) {\n hrTime[0] -= 1\n hrTime[1] += 1000_000_000\n }\n millis =\n (startHrMillis as number) +\n hrTime[0] * 1000 +\n Math.floor(hrTime[1] / 1000_000)\n }\n const nanos = String(hrTime[1] % 1000_000)\n return String(millis) + zeroPadding.substr(0, 6 - nanos.length) + nanos\n } else {\n const millis = Date.now()\n if (millis !== lastMillis) {\n lastMillis = millis\n stepsInMillis = 0\n } else {\n stepsInMillis++\n }\n const nanos = String(stepsInMillis)\n return String(millis) + zeroPadding.substr(0, 6 - nanos.length) + nanos\n }\n}\n\nfunction micros(): string {\n if (!process.env.BUILD_BROWSER && useHrTime) {\n const hrTime = process.hrtime() as [number, number]\n const micros = String(Math.trunc(hrTime[1] / 1000) % 1000)\n return (\n String(Date.now()) + zeroPadding.substr(0, 3 - micros.length) + micros\n )\n } else {\n return String(Date.now()) + zeroPadding.substr(0, 3)\n }\n}\nfunction millis(): string {\n return String(Date.now())\n}\nfunction seconds(): string {\n return String(Math.floor(Date.now() / 1000))\n}\n\n/**\n * Exposes functions that creates strings that represent a timestamp that\n * can be used in the line protocol. Micro and nano timestamps are emulated\n * depending on the js platform in use.\n */\nexport const currentTime = {\n s: seconds as () => string,\n ms: millis as () => string,\n us: micros as () => string,\n ns: nanos as () => string,\n seconds: seconds as () => string,\n millis: millis as () => string,\n micros: micros as () => string,\n nanos: nanos as () => string,\n}\n\n/**\n * dateToProtocolTimestamp provides converters for JavaScript Date to InfluxDB Write Protocol Timestamp. Keys are supported precisions.\n */\nexport const dateToProtocolTimestamp = {\n s: (d: Date): string => `${Math.floor(d.getTime() / 1000)}`,\n ms: (d: Date): string => `${d.getTime()}`,\n us: (d: Date): string => `${d.getTime()}000`,\n ns: (d: Date): string => `${d.getTime()}000000`,\n}\n\n/**\n * convertTimeToNanos converts Point's timestamp to a string.\n * @param value - supported timestamp value\n * @returns line protocol value\n */\nexport function convertTimeToNanos(\n value: string | number | Date | undefined\n): string | undefined {\n if (value === undefined) {\n return nanos()\n } else if (typeof value === 'string') {\n return value.length > 0 ? value : undefined\n } else if (value instanceof Date) {\n return `${value.getTime()}000000`\n } else if (typeof value === 'number') {\n return String(Math.floor(value))\n } else {\n return String(value)\n }\n}\n\nexport const convertTime = (\n value: string | number | Date | undefined,\n precision: WritePrecision = 'ns'\n): string | undefined => {\n if (value === undefined) {\n return currentTime[precision]()\n } else if (typeof value === 'string') {\n return value.length > 0 ? value : undefined\n } else if (value instanceof Date) {\n return dateToProtocolTimestamp[precision](value)\n } else if (typeof value === 'number') {\n return String(Math.floor(value))\n } else {\n return String(value)\n }\n}\n","type Defined<T> = Exclude<T, undefined>\n\n/**\n * allows to throw error as expression\n */\nexport const throwReturn = <T>(err: Error): Defined<T> => {\n throw err\n}\n\nexport const isDefined = <T>(value: T): value is Defined<T> =>\n value !== undefined\n\nexport const isArrayLike = <T>(value: any): value is ArrayLike<T> =>\n value instanceof Array ||\n (value instanceof Object &&\n typeof value.length === 'number' &&\n (value.length === 0 ||\n Object.getOwnPropertyNames(value).some((x) => x === '0')))\n\nexport const createInt32Uint8Array = (value: number): Uint8Array => {\n const bytes = new Uint8Array(4)\n bytes[0] = value >> (8 * 0)\n bytes[1] = value >> (8 * 1)\n bytes[2] = value >> (8 * 2)\n bytes[3] = value >> (8 * 3)\n return bytes\n}\n\nexport const collectAll = async <T>(\n generator: AsyncGenerator<T, any, any>\n): Promise<T[]> => {\n const results: T[] = []\n for await (const value of generator) {\n results.push(value)\n }\n return results\n}\n\n/**\n * Check if an input value is a valid number.\n *\n * @param value - The value to check\n * @returns Returns true if the value is a valid number else false\n */\nexport const isNumber = (value?: number | string | null): boolean => {\n if (value === null || undefined) {\n return false\n }\n\n if (\n typeof value === 'string' &&\n (value === '' || value.indexOf(' ') !== -1)\n ) {\n return false\n }\n\n return value !== '' && !isNaN(Number(value?.toString()))\n}\n\n/**\n * Check if an input value is a valid unsigned number.\n *\n * @param value - The value to check\n * @returns Returns true if the value is a valid unsigned number else false\n */\nexport const isUnsignedNumber = (value?: number | string | null): boolean => {\n if (!isNumber(value)) {\n return false\n }\n\n if (typeof value === 'string') {\n return Number(value) >= 0\n }\n\n return typeof value === 'number' && value >= 0\n}\n","import {Point} from '../Point'\nimport {isArrayLike, isDefined} from './common'\n\n/**\n * The `WritableData` type represents different types of data that can be written.\n * The data can either be a uniform ArrayLike collection or a single value of the following types:\n *\n * - `Point`: Represents a {@link Point} object.\n *\n * - `string`: Represents lines of the [Line Protocol](https://bit.ly/2QL99fu).\n */\nexport type WritableData = ArrayLike<string> | ArrayLike<Point> | string | Point\n\nexport const writableDataToLineProtocol = (\n data: WritableData,\n defaultTags?: {[key: string]: string}\n): string[] => {\n const arrayData = (\n isArrayLike(data) && typeof data !== 'string'\n ? Array.from(data as any)\n : [data]\n ) as string[] | Point[]\n if (arrayData.length === 0) return []\n\n const isLine = typeof arrayData[0] === 'string'\n\n return isLine\n ? (arrayData as string[])\n : (arrayData as Point[])\n .map((p) => p.toLineProtocol(undefined, defaultTags))\n .filter(isDefined)\n}\n","import {Point} from './Point'\n\nexport type PointFieldType =\n | 'float'\n | 'integer'\n | 'uinteger'\n | 'string'\n | 'boolean'\n\ntype FieldEntryFloat = ['float', number]\ntype FieldEntryInteger = ['integer', number]\ntype FieldEntryUinteger = ['uinteger', number]\ntype FieldEntryString = ['string', string]\ntype FieldEntryBoolean = ['boolean', boolean]\n\ntype FieldEntry =\n | FieldEntryFloat\n | FieldEntryInteger\n | FieldEntryUinteger\n | FieldEntryString\n | FieldEntryBoolean\n\nconst inferType = (\n value: number | string | boolean | undefined\n): PointFieldType | undefined => {\n if (typeof value === 'number') return 'float'\n else if (typeof value === 'string') return 'string'\n else if (typeof value === 'boolean') return 'boolean'\n else return undefined\n}\n\nexport class GetFieldTypeMissmatchError extends Error {\n /* istanbul ignore next */\n constructor(\n fieldName: string,\n expectedType: PointFieldType,\n actualType: PointFieldType\n ) {\n super(\n `field ${fieldName} of type ${actualType} doesn't match expected type ${expectedType}!`\n )\n this.name = 'GetFieldTypeMissmatchError'\n Object.setPrototypeOf(this, GetFieldTypeMissmatchError.prototype)\n }\n}\n\n/**\n * Point defines values of a single measurement.\n */\nexport class PointValues {\n private _name: string | undefined\n private _time: string | number | Date | undefined\n private _tags: {[key: string]: string} = {}\n private _fields: {[key: string]: FieldEntry} = {}\n\n /**\n * Create an empty PointValues.\n */\n constructor() {}\n\n /**\n * Get measurement name. Can be undefined if not set.\n * It will return undefined when querying with SQL Query.\n *\n * @returns measurement name or undefined\n */\n getMeasurement(): string | undefined {\n return this._name\n }\n\n /**\n * Sets point's measurement.\n *\n * @param name - measurement name\n * @returns this\n */\n public setMeasurement(name: string): PointValues {\n this._name = name\n return this\n }\n\n /**\n * Get timestamp. Can be undefined if not set.\n *\n * @returns timestamp or undefined\n */\n public getTimestamp(): Date | number | string | undefined {\n return this._time\n }\n\n /**\n * Sets point timestamp. Timestamp can be specified as a Date (preferred), number, string\n * or an undefined value. An undefined value instructs to assign a local timestamp using\n * the client's clock. An empty string can be used to let the server assign\n * the timestamp. A number value represents time as a count of time units since epoch, the\n * exact time unit then depends on the {@link InfluxDBClient.default.write | precision} of the API\n * that writes the point.\n *\n * Beware that the current time in nanoseconds can't precisely fit into a JS number,\n * which can hold at most 2^53 integer number. Nanosecond precision numbers are thus supplied as\n * a (base-10) string. An application can also use ES2020 BigInt to represent nanoseconds,\n * BigInt's `toString()` returns the required high-precision string.\n *\n * Note that InfluxDB requires the timestamp to fit into int64 data type.\n *\n * @param value - point time\n * @returns this\n */\n public setTimestamp(value: Date | number | string | undefined): PointValues {\n this._time = value\n return this\n }\n\n /**\n * Gets value of tag with given name. Returns undefined if tag not found.\n *\n * @param name - tag name\n * @returns tag value or undefined\n */\n public getTag(name: string): string | undefined {\n return this._tags[name]\n }\n\n /**\n * Sets a tag. The caller has to ensure that both name and value are not empty\n * and do not end with backslash.\n *\n * @param name - tag name\n * @param value - tag value\n * @returns this\n */\n public setTag(name: string, value: string): PointValues {\n this._tags[name] = value\n return this\n }\n\n /**\n * Removes a tag with the specified name if it exists; otherwise, it does nothing.\n *\n * @param name - The name of the tag to be removed.\n * @returns this\n */\n public removeTag(name: string): PointValues {\n delete this._tags[name]\n return this\n }\n\n /**\n * Gets an array of tag names.\n *\n * @returns An array of tag names.\n */\n public getTagNames(): string[] {\n return Object.keys(this._tags)\n }\n\n /**\n * Gets the float field value associated with the specified name.\n * Throws if actual type of field with given name is not float.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @throws {@link GetFieldTypeMissmatchError} Actual type of field doesn't match float type.\n * @returns The float field value or undefined.\n */\n public getFloatField(name: string): number | undefined {\n return this.getField(name, 'float')\n }\n\n /**\n * Sets a number field.\n *\n * @param name - field name\n * @param value - field value\n * @returns this\n * @throws NaN/Infinity/-Infinity is supplied\n */\n public setFloatField(name: string, value: number | any): PointValues {\n let val: number\n if (typeof value === 'number') {\n val = value\n } else {\n val = parseFloat(value)\n }\n if (!isFinite(val)) {\n throw new Error(`invalid float value for field '${name}': '${value}'!`)\n }\n\n this._fields[name] = ['float', val]\n return this\n }\n\n /**\n * Gets the integer field value associated with the specified name.\n * Throws if actual type of field with given name is not integer.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @throws {@link GetFieldTypeMissmatchError} Actual type of field doesn't match integer type.\n * @returns The integer field value or undefined.\n */\n public getIntegerField(name: string): number | undefined {\n return this.getField(name, 'integer')\n }\n\n /**\n * Sets an integer field.\n *\n * @param name - field name\n * @param value - field value\n * @returns this\n * @throws NaN or out of int64 range value is supplied\n */\n public setIntegerField(name: string, value: number | any): PointValues {\n let val: number\n if (typeof value === 'number') {\n val = value\n } else {\n val = parseInt(String(value))\n }\n if (isNaN(val) || val <= -9223372036854776e3 || val >= 9223372036854776e3) {\n throw new Error(`invalid integer value for field '${name}': '${value}'!`)\n }\n this._fields[name] = ['integer', Math.floor(val)]\n return this\n }\n\n /**\n * Gets the uint field value associated with the specified name.\n * Throws if actual type of field with given name is not uint.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @throws {@link GetFieldTypeMissmatchError} Actual type of field doesn't match uint type.\n * @returns The uint field value or undefined.\n */\n public getUintegerField(name: string): number | undefined {\n return this.getField(name, 'uinteger')\n }\n\n /**\n * Sets an unsigned integer field.\n *\n * @param name - field name\n * @param value - field value\n * @returns this\n * @throws NaN out of range value is supplied\n */\n public setUintegerField(name: string, value: number | any): PointValues {\n if (typeof value === 'number') {\n if (isNaN(value) || value < 0 || value > Number.MAX_SAFE_INTEGER) {\n throw new Error(`uint value for field '${name}' out of range: ${value}`)\n }\n this._fields[name] = ['uinteger', Math.floor(value as number)]\n } else {\n const strVal = String(value)\n for (let i = 0; i < strVal.length; i++) {\n const code = strVal.charCodeAt(i)\n if (code < 48 || code > 57) {\n throw new Error(\n `uint value has an unsupported character at pos ${i}: ${value}`\n )\n }\n }\n if (\n strVal.length > 20 ||\n (strVal.length === 20 &&\n strVal.localeCompare('18446744073709551615') > 0)\n ) {\n throw new Error(\n `uint value for field '${name}' out of range: ${strVal}`\n )\n }\n this._fields[name] = ['uinteger', +strVal]\n }\n return this\n }\n\n /**\n * Gets the string field value associated with the specified name.\n * Throws if actual type of field with given name is not string.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @throws {@link GetFieldTypeMissmatchError} Actual type of field doesn't match string type.\n * @returns The string field value or undefined.\n */\n public getStringField(name: string): string | undefined {\n return this.getField(name, 'string')\n }\n\n /**\n * Sets a string field.\n *\n * @param name - field name\n * @param value - field value\n * @returns this\n */\n public setStringField(name: string, value: string | any): PointValues {\n if (value !== null && value !== undefined) {\n if (typeof value !== 'string') value = String(value)\n this._fields[name] = ['string', value]\n }\n return this\n }\n\n /**\n * Gets the boolean field value associated with the specified name.\n * Throws if actual type of field with given name is not boolean.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @throws {@link GetFieldTypeMissmatchError} Actual type of field doesn't match boolean type.\n * @returns The boolean field value or undefined.\n */\n public getBooleanField(name: string): boolean | undefined {\n return this.getField(name, 'boolean')\n }\n\n /**\n * Sets a boolean field.\n *\n * @param name - field name\n * @param value - field value\n * @returns this\n */\n public setBooleanField(name: string, value: boolean | any): PointValues {\n this._fields[name] = ['boolean', !!value]\n return this\n }\n\n /**\n * Get field of numeric type.\n * Throws if actual type of field with given name is not given numeric type.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @param type - field numeric type\n * @throws {@link GetFieldTypeMissmatchError} Actual type of field doesn't match provided numeric type.\n * @returns this\n */\n public getField(\n name: string,\n type: 'float' | 'integer' | 'uinteger'\n ): number | undefined\n /**\n * Get field of string type.\n * Throws if actual type of field with given name is not string.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @param type - field string type\n * @throws {@link GetFieldTypeMissmatchError} Actual type of field doesn't match provided 'string' type.\n * @returns this\n */\n public getField(name: string, type: 'string'): string | undefined\n /**\n * Get field of boolean type.\n * Throws if actual type of field with given name is not boolean.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @param type - field boolean type\n * @throws {@link GetFieldTypeMissmatchError} Actual type of field doesn't match provided 'boolean' type.\n * @returns this\n */\n public getField(name: string, type: 'boolean'): boolean | undefined\n /**\n * Get field without type check.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @returns this\n */\n public getField(name: string): number | string | boolean | undefined\n public getField(\n name: string,\n type?: PointFieldType\n ): number | string | boolean | undefined {\n const fieldEntry = this._fields[name]\n if (!fieldEntry) return undefined\n const [actualType, value] = fieldEntry\n if (type !== undefined && type !== actualType)\n throw new GetFieldTypeMissmatchError(name, type, actualType)\n return value\n }\n\n /**\n * Gets the type of field with given name, if it exists.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @returns The field type or undefined.\n */\n public getFieldType(name: string): PointFieldType | undefined {\n const fieldEntry = this._fields[name]\n if (!fieldEntry) return undefined\n return fieldEntry[0]\n }\n\n /**\n * Sets field based on provided type.\n *\n * @param name - field name\n * @param value - field value\n * @param type - field type\n * @returns this\n */\n public setField(\n name: string,\n value: any,\n type?: PointFieldType\n ): PointValues {\n const inferedType = type ?? inferType(value)\n switch (inferedType) {\n case 'string':\n return this.setStringField(name, value)\n case 'boolean':\n return this.setBooleanField(name, value)\n case 'float':\n return this.setFloatField(name, value)\n case 'integer':\n return this.setIntegerField(name, value)\n case 'uinteger':\n return this.setUintegerField(name, value)\n case undefined:\n return this\n default:\n throw new Error(\n `invalid field type for field '${name}': type -> ${type}, value -> ${value}!`\n )\n }\n }\n\n /**\n * Add fields according to their type. All numeric type is considered float\n *\n * @param fields - name-value map\n * @returns this\n */\n public setFields(fields: {\n [key: string]: number | boolean | string\n }): PointValues {\n for (const [name, value] of Object.entries(fields)) {\n this.setField(name, value)\n }\n return this\n }\n\n /**\n * Removes a field with the specified name if it exists; otherwise, it does nothing.\n *\n * @param name - The name of the field to be removed.\n * @returns this\n */\n public removeField(name: string): PointValues {\n delete this._fields[name]\n return this\n }\n\n /**\n * Gets an array of field names associated with this object.\n *\n * @returns An array of field names.\n */\n public getFieldNames(): string[] {\n return Object.keys(this._fields)\n }\n\n /**\n * Checks if this object has any fields.\n *\n * @returns true if fields are present, false otherwise.\n */\n public hasFields(): boolean {\n return this.getFieldNames().length > 0\n }\n\n /**\n * Creates a copy of this object.\n *\n * @returns A new instance with same values.\n */\n copy(): PointValues {\n const copy = new PointValues()\n copy._name = this._name\n copy._time = this._time\n copy._tags = Object.fromEntries(Object.entries(this._tags))\n copy._fields = Object.fromEntries(\n Object.entries(this._fields).map((entry) => [...entry])\n )\n return copy\n }\n\n /**\n * Creates new Point with this as values.\n *\n * @returns Point from this values.\n */\n public asPoint(measurement?: string): Point {\n return Point.fromValues(\n measurement ? this.setMeasurement(measurement) : this\n )\n }\n}\n","import {TimeConverter} from './WriteApi'\nimport {convertTimeToNanos, convertTime} from './util/time'\nimport {escape} from './util/escape'\nimport {WritePrecision} from './options'\nimport {PointFieldType, PointValues} from './PointValues'\n\nconst fieldToLPString: {\n (type: 'float', value: number): string\n (type: 'integer', value: number): string\n (type: 'uinteger', value: number): string\n (type: 'string', value: string): string\n (type: 'boolean', value: boolean): string\n (type: PointFieldType, value: number | string | boolean): string\n} = (type: PointFieldType, value: number | string | boolean): string => {\n switch (type) {\n case 'string':\n return escape.quoted(value as string)\n case 'boolean':\n return value ? 'T' : 'F'\n case 'float':\n return `${value}`\n case 'integer':\n return `${value}i`\n case 'uinteger':\n return `${value}u`\n }\n}\n\n/**\n * Point defines values of a single measurement.\n */\nexport class Point {\n private readonly _values: PointValues\n\n /**\n * Create a new Point with specified a measurement name.\n *\n * @param measurementName - the measurement name\n */\n private constructor(measurementName: string)\n /**\n * Create a new Point with given values.\n * After creating Point, it's values shouldn't be modified directly by PointValues object.\n *\n * @param values - point values\n */\n private constructor(values: PointValues)\n private constructor(arg0?: PointValues | string) {\n if (arg0 instanceof PointValues) {\n this._values = arg0\n } else {\n this._values = new PointValues()\n }\n\n if (typeof arg0 === 'string') this._values.setMeasurement(arg0)\n }\n\n /**\n * Creates new Point with given measurement.\n *\n * @param name - measurement name\n * @returns new Point\n */\n public static measurement(name: string): Point {\n return new Point(name)\n }\n\n /**\n * Creates new point from PointValues object.\n * Can throw error if measurement missing.\n *\n * @param values - point values object with measurement\n * @throws missing measurement\n * @returns new point from values\n */\n public static fromValues(values: PointValues): Point {\n if (!values.getMeasurement() || values.getMeasurement() === '') {\n throw new Error('Cannot convert values to point without measurement set!')\n }\n return new Point(values)\n }\n\n /**\n * Get measurement name.\n * It will return undefined when querying with SQL Query.\n *\n * @returns measurement name\n */\n public getMeasurement(): string {\n return this._values.getMeasurement() as string\n }\n\n /**\n * Sets point's measurement.\n *\n * @param name - measurement name\n * @returns this\n */\n public setMeasurement(name: string): Point {\n if (name !== '') {\n this._values.setMeasurement(name)\n }\n return this\n }\n\n /**\n * Get timestamp. Can be undefined if not set.\n *\n * @returns timestamp or undefined\n */\n public getTimestamp(): Date | number | string | undefined {\n return this._values.getTimestamp()\n }\n\n /**\n * Sets point timestamp. Timestamp can be specified as a Date (preferred), number, string\n * or an undefined value. An undefined value instructs to assign a local timestamp using\n * the client's clock. An empty string can be used to let the server assign\n * the timestamp. A number value represents time as a count of time units since epoch, the\n * exact time unit then depends on the {@link InfluxDBClient.default.write | precision} of the API\n * that writes the point.\n *\n * Beware that the current time in nanoseconds can't precisely fit into a JS number,\n * which can hold at most 2^53 integer number. Nanosecond precision numbers are thus supplied as\n * a (base-10) string. An application can also use ES2020 BigInt to represent nanoseconds,\n * BigInt's `toString()` returns the required high-precision string.\n *\n * Note that InfluxDB requires the timestamp to fit into int64 data type.\n *\n * @param value - point time\n * @returns this\n */\n public setTimestamp(value: Date | number | string | undefined): Point {\n this._values.setTimestamp(value)\n return this\n }\n\n /**\n * Gets value of tag with given name. Returns undefined if tag not found.\n *\n * @param name - tag name\n * @returns tag value or undefined\n */\n public getTag(name: string): string | undefined {\n return this._values.getTag(name)\n }\n\n /**\n * Sets a tag. The caller has to ensure that both name and value are not empty\n * and do not end with backslash.\n *\n * @param name - tag name\n * @param value - tag value\n * @returns this\n */\n public setTag(name: string, value: string): Point {\n this._values.setTag(name, value)\n return this\n }\n\n /**\n * Removes a tag with the specified name if it exists; otherwise, it does nothing.\n *\n * @param name - The name of the tag to be removed.\n * @returns this\n */\n public removeTag(name: string): Point {\n this._values.removeTag(name)\n return this\n }\n\n /**\n * Gets an array of tag names.\n *\n * @returns An array of tag names.\n */\n public getTagNames(): string[] {\n return this._values.getTagNames()\n }\n\n /**\n * Gets the float field value associated with the specified name.\n * Throws if actual type of field with given name is not float.\n * If the field is not present, returns undefined.\n *\n * @param name - field name\n * @throws {@link PointValues.GetFieldTypeMissmatchError} Actual type of field doesn't match float type.\n * @returns The float field value or undefined.\n */\n public getFloatField(name: string): number | undefined {\n return this._values.getFloatField(name)\n }\n\n /**\n