From 75602e0a8cb4c063e6a9653fa07f5369399a7960 Mon Sep 17 00:00:00 2001 From: Dudi Zimberknopf Date: Sun, 1 Dec 2024 11:06:23 +0200 Subject: [PATCH 1/2] add disconnect to clients --- src/clients/client.ts | 84 ++++++---- src/clients/cluster.ts | 246 +++++++++++++++++------------- src/clients/nullClient.ts | 3 + src/clients/sentinel.ts | 169 +++++++++++---------- src/clients/single.ts | 312 +++++++++++++++++++------------------- src/falkordb.ts | 2 +- 6 files changed, 448 insertions(+), 368 deletions(-) diff --git a/src/clients/client.ts b/src/clients/client.ts index 5ace078..33bb9c7 100644 --- a/src/clients/client.ts +++ b/src/clients/client.ts @@ -1,48 +1,76 @@ -import { RedisCommandArgument } from "@redis/client/dist/lib/commands" -import { QueryOptions } from "../commands" -import { ConstraintType, EntityType, GraphReply } from "../graph" -import FalkorDB from "../falkordb" -import { SingleGraphConnection } from "./single" +import { RedisCommandArgument } from "@redis/client/dist/lib/commands"; +import { QueryOptions } from "../commands"; +import { ConstraintType, EntityType, GraphReply } from "../graph"; +import FalkorDB from "../falkordb"; +import { SingleGraphConnection } from "./single"; // A generic client interface for Redis clients export interface Client { + init(falkordb: FalkorDB): Promise; - init(falkordb: FalkorDB): Promise + list(): Promise>; - list(): Promise> + configGet( + configKey: string + ): Promise<(string | number)[] | (string | number)[][]>; - configGet(configKey: string): Promise<(string | number)[] | (string | number)[][]> + configSet(configKey: string, value: number | string): Promise; - configSet(configKey: string, value: number | string): Promise + info(section?: string): Promise<(string | string[])[]>; - info(section?: string): Promise<(string | string[])[]> + query( + graph: string, + query: RedisCommandArgument, + options?: QueryOptions, + compact?: boolean + ): Promise; - query(graph: string, query: RedisCommandArgument,options?: QueryOptions, compact?: boolean): Promise + profile(graph: string, query: RedisCommandArgument): Promise; - profile(graph: string, query: RedisCommandArgument): Promise + roQuery( + graph: string, + query: RedisCommandArgument, + options?: QueryOptions, + compact?: boolean + ): Promise; - roQuery(graph: string, query: RedisCommandArgument, options?: QueryOptions, compact?: boolean): Promise + copy(srcGraph: string, destGraph: string): Promise; - copy(srcGraph: string, destGraph: string): Promise + delete(graph: string): Promise; - delete(graph: string): Promise + explain(graph: string, query: string): Promise; - explain(graph: string, query: string): Promise + slowLog(graph: string): Promise< + { + timestamp: Date; + command: string; + query: string; + took: number; + }[] + >; - slowLog(graph: string) : Promise<{ - timestamp: Date; - command: string; - query: string; - took: number; - }[]> + constraintCreate( + graph: string, + constraintType: ConstraintType, + entityType: EntityType, + label: string, + ...properties: string[] + ): Promise; - constraintCreate(graph: string, constraintType: ConstraintType, entityType: EntityType, - label: string, ...properties: string[]) : Promise + constraintDrop( + graph: string, + constraintType: ConstraintType, + entityType: EntityType, + label: string, + ...properties: string[] + ): Promise; - constraintDrop(graph: string, constraintType: ConstraintType, entityType: EntityType, - label: string, ...properties: string[]) : Promise + /** + * @deprecated Use `disconnect` instead + */ + quit(): Promise; - quit(): Promise + disconnect(): Promise; - getConnection(): Promise; + getConnection(): Promise; } diff --git a/src/clients/cluster.ts b/src/clients/cluster.ts index be5ea06..e5a2525 100644 --- a/src/clients/cluster.ts +++ b/src/clients/cluster.ts @@ -1,116 +1,154 @@ import { Client } from "./client"; import { ConstraintType, EntityType } from "../graph"; -import { RedisCommandArgument, RedisFunctions, RedisScripts } from "@redis/client/dist/lib/commands"; +import { + RedisCommandArgument, + RedisFunctions, + RedisScripts, +} from "@redis/client/dist/lib/commands"; import commands, { QueryOptions } from "../commands"; import { createCluster, RedisClusterType } from "@redis/client"; import FalkorDB, { TypedRedisClusterClientOptions } from "../falkordb"; import { SingleGraphConnection } from "./single"; import { RedisClusterClientOptions } from "@redis/client/dist/lib/cluster"; -import * as lodash from 'lodash' -export type ClusterGraphConnection = RedisClusterType<{ falkordb: typeof commands }, RedisFunctions, RedisScripts>; +import * as lodash from "lodash"; +export type ClusterGraphConnection = RedisClusterType< + { falkordb: typeof commands }, + RedisFunctions, + RedisScripts +>; /** * A client that connects to a Redis Cluster. */ export class Cluster implements Client { - - #client: ClusterGraphConnection; - - constructor(client: SingleGraphConnection) { - - // Convert the single client options to a cluster client options - const redisClusterOption = client.options as TypedRedisClusterClientOptions; - redisClusterOption.rootNodes = [client.options as RedisClusterClientOptions]; - - // Remove the URL from the defaults so it won't override the dynamic cluster URLs - const defaults = lodash.cloneDeep(client.options); - defaults?.url && delete defaults.url; - - redisClusterOption.defaults = defaults; - redisClusterOption.maxCommandRedirections = 100000; - client.disconnect(); - this.#client = createCluster<{ falkordb: typeof commands }, RedisFunctions, RedisScripts>(redisClusterOption) - } - - async getConnection() { - const connection = this.#client.nodeClient(this.#client.getRandomNode()); - return connection instanceof Promise ? await connection : connection; - } - - async init(falkordb: FalkorDB) { - await this.#client - .on('error', err => falkordb.emit('error', err)) // Forward errors - .connect(); - } - - async query(graph: string, query: RedisCommandArgument, options?: QueryOptions, compact=true) { - return this.#client.falkordb.query(graph, query, options, compact) - } - async roQuery(graph: string, query: RedisCommandArgument, options?: QueryOptions, compact=true) { - return this.#client.falkordb.roQuery(graph, query, options, compact) - } - - async delete(graph: string) { - const reply = this.#client.falkordb.delete(graph) - return reply.then(() => { }) - } - - async explain(graph: string, query: string) { - return this.#client.falkordb.explain(graph, query) - } - - async list(): Promise> { - return this.#client.falkordb.list() - } - - async configGet(configKey: string) { - return this.#client.falkordb.configGet(configKey) - } - - async configSet(configKey: string, value: number | string) { - const reply = this.#client.falkordb.configSet(configKey, value) - return reply.then(() => { }) - } - - async info(section?: string) { - return this.#client.falkordb.info(section) - } - - async copy(srcGraph: string, destGraph: string) { - return this.#client.falkordb.copy(srcGraph, destGraph) - } - - slowLog(graph: string) { - return this.#client.falkordb.slowLog(graph) - } - async constraintCreate(graph: string, constraintType: ConstraintType, entityType: EntityType, label: string, ...properties: string[]) { - const reply = this.#client.falkordb.constraintCreate( - graph, - constraintType, - entityType, - label, - ...properties - ) - return reply.then(() => { }) - } - - async constraintDrop(graph: string, constraintType: ConstraintType, entityType: EntityType, label: string, ...properties: string[]) { - const reply = this.#client.falkordb.constraintDrop( - graph, - constraintType, - entityType, - label, - ...properties - ) - return reply.then(() => { }) - } - - async profile(graph: string, query: string) { - return this.#client.falkordb.profile( graph, query) - } - - async quit() { - const reply = this.#client.quit(); - return reply.then(() => {}) - } -} \ No newline at end of file + #client: ClusterGraphConnection; + + constructor(client: SingleGraphConnection) { + // Convert the single client options to a cluster client options + const redisClusterOption = client.options as TypedRedisClusterClientOptions; + redisClusterOption.rootNodes = [ + client.options as RedisClusterClientOptions, + ]; + + // Remove the URL from the defaults so it won't override the dynamic cluster URLs + const defaults = lodash.cloneDeep(client.options); + defaults?.url && delete defaults.url; + + redisClusterOption.defaults = defaults; + redisClusterOption.maxCommandRedirections = 100000; + client.disconnect(); + this.#client = createCluster< + { falkordb: typeof commands }, + RedisFunctions, + RedisScripts + >(redisClusterOption); + } + + async getConnection() { + const connection = this.#client.nodeClient(this.#client.getRandomNode()); + return connection instanceof Promise ? await connection : connection; + } + + async init(falkordb: FalkorDB) { + await this.#client + .on("error", (err) => falkordb.emit("error", err)) // Forward errors + .connect(); + } + + async query( + graph: string, + query: RedisCommandArgument, + options?: QueryOptions, + compact = true + ) { + return this.#client.falkordb.query(graph, query, options, compact); + } + async roQuery( + graph: string, + query: RedisCommandArgument, + options?: QueryOptions, + compact = true + ) { + return this.#client.falkordb.roQuery(graph, query, options, compact); + } + + async delete(graph: string) { + const reply = this.#client.falkordb.delete(graph); + return reply.then(() => {}); + } + + async explain(graph: string, query: string) { + return this.#client.falkordb.explain(graph, query); + } + + async list(): Promise> { + return this.#client.falkordb.list(); + } + + async configGet(configKey: string) { + return this.#client.falkordb.configGet(configKey); + } + + async configSet(configKey: string, value: number | string) { + const reply = this.#client.falkordb.configSet(configKey, value); + return reply.then(() => {}); + } + + async info(section?: string) { + return this.#client.falkordb.info(section); + } + + async copy(srcGraph: string, destGraph: string) { + return this.#client.falkordb.copy(srcGraph, destGraph); + } + + slowLog(graph: string) { + return this.#client.falkordb.slowLog(graph); + } + async constraintCreate( + graph: string, + constraintType: ConstraintType, + entityType: EntityType, + label: string, + ...properties: string[] + ) { + const reply = this.#client.falkordb.constraintCreate( + graph, + constraintType, + entityType, + label, + ...properties + ); + return reply.then(() => {}); + } + + async constraintDrop( + graph: string, + constraintType: ConstraintType, + entityType: EntityType, + label: string, + ...properties: string[] + ) { + const reply = this.#client.falkordb.constraintDrop( + graph, + constraintType, + entityType, + label, + ...properties + ); + return reply.then(() => {}); + } + + async profile(graph: string, query: string) { + return this.#client.falkordb.profile(graph, query); + } + + async quit() { + return this.disconnect(); + } + + async disconnect(): Promise { + const reply = this.#client.disconnect(); + return reply.then(() => {}); + } +} diff --git a/src/clients/nullClient.ts b/src/clients/nullClient.ts index e2dfd86..6608258 100644 --- a/src/clients/nullClient.ts +++ b/src/clients/nullClient.ts @@ -66,4 +66,7 @@ export class NullClient implements Client { quit(): Promise { throw new Error("Method not implemented."); } + disconnect(): Promise { + throw new Error("Method not implemented."); + } } \ No newline at end of file diff --git a/src/clients/sentinel.ts b/src/clients/sentinel.ts index baf38a0..ac26258 100644 --- a/src/clients/sentinel.ts +++ b/src/clients/sentinel.ts @@ -1,98 +1,103 @@ -import * as tls from 'tls'; +import * as tls from "tls"; import { Single, SingleGraphConnection } from "./single"; import FalkorDB, { TypedRedisClientOptions } from "../falkordb"; import { createClient, RedisFunctions, RedisScripts } from "@redis/client"; -import commands from '../commands'; - +import commands from "../commands"; function extractDetails(masters: Array>) { - const allDetails: Record[] = []; - for (const master of masters) { - const details: Record = {}; - for (let i = 0; i < master.length; i += 2) { - details[master[i]] = master[i + 1]; - } - allDetails.push(details); + const allDetails: Record[] = []; + for (const master of masters) { + const details: Record = {}; + for (let i = 0; i < master.length; i += 2) { + details[master[i]] = master[i + 1]; } - return allDetails; + allDetails.push(details); + } + return allDetails; } export class Sentinel extends Single { + private sentinelClient!: SingleGraphConnection; + + init(falkordb: FalkorDB): Promise { + const redisOption = (this.client.options ?? {}) as TypedRedisClientOptions; + return this.tryConnectSentinelServer(this.client, redisOption, falkordb); + } + + /** + * Connect to the server using the details from sentinel server + * Register error event to reconnect on error from the sentinel server + */ + private async tryConnectSentinelServer( + client: SingleGraphConnection, + redisOption: TypedRedisClientOptions, + falkordb: FalkorDB + ) { + // TODO support multi sentinels + const masters = await client.falkordb.sentinelMasters(); + const details = extractDetails(masters); + + if (details.length > 1) { + throw new Error("Multiple masters are not supported"); + } - private sentinelClient!: SingleGraphConnection; - - init(falkordb: FalkorDB): Promise { - const redisOption = (this.client.options ?? {}) as TypedRedisClientOptions; - return this.tryConnectSentinelServer(this.client, redisOption, falkordb); - } - - /** - * Connect to the server using the details from sentinel server - * Register error event to reconnect on error from the sentinel server - */ - private async tryConnectSentinelServer(client: SingleGraphConnection, redisOption: TypedRedisClientOptions, falkordb: FalkorDB) { - - // TODO support multi sentinels - const masters = await client.falkordb.sentinelMasters(); - const details = extractDetails(masters); - - if (details.length > 1) { - throw new Error('Multiple masters are not supported'); + // Connect to the server with the details from sentinel + const socketOptions: tls.ConnectionOptions = { + ...redisOption.socket, + host: details[0]["ip"] as string, + port: parseInt(details[0]["port"]), + }; + const serverOptions: TypedRedisClientOptions = { + ...redisOption, + socket: socketOptions, + }; + const realClient = createClient< + { falkordb: typeof commands }, + RedisFunctions, + RedisScripts + >(serverOptions); + + // Save sentinel client to quit on quit() + this.sentinelClient = client; + + // Set original client as sentinel and server client as client + this.client = realClient; + + await realClient + .on("error", async (err) => { + console.debug("Error on server connection", err); + + // Disconnect the client to avoid further errors and retries + realClient.disconnect(); + + // If error occurs on previous server connection, no need to reconnect + if (this.client !== realClient) { + return; } - - // Connect to the server with the details from sentinel - const socketOptions: tls.ConnectionOptions = { - ...redisOption.socket, - host: details[0]['ip'] as string, - port: parseInt(details[0]['port']) - }; - const serverOptions: TypedRedisClientOptions = { - ...redisOption, - socket: socketOptions - }; - const realClient = createClient<{ falkordb: typeof commands }, RedisFunctions, RedisScripts>(serverOptions) - - // Save sentinel client to quit on quit() - this.sentinelClient = client; - // Set original client as sentinel and server client as client - this.client = realClient; + try { + await this.tryConnectSentinelServer(client, redisOption, falkordb); + console.debug("Connected to server"); + } catch (e) { + console.debug("Error on server reconnect", e); - await realClient - .on('error', async err => { - - console.debug('Error on server connection', err) - - // Disconnect the client to avoid further errors and retries - realClient.disconnect(); - - // If error occurs on previous server connection, no need to reconnect - if (this.client !== realClient) { - return; - } - - try { - await this.tryConnectSentinelServer(client, redisOption, falkordb) - console.debug('Connected to server') - } catch (e) { - console.debug('Error on server reconnect', e) - - // Forward errors if reconnection fails - falkordb.emit('error', err) - } - }) - .connect(); - } - - async quit() { - const promises = [ - super.quit() - ]; - if (this.sentinelClient) { - const reply = this.sentinelClient.quit(); - promises.push(reply.then(() => {})) + // Forward errors if reconnection fails + falkordb.emit("error", err); } - return Promise.all(promises).then(() => {}); + }) + .connect(); + } + + quit() { + return this.disconnect(); + } + + async disconnect() { + const promises = [super.disconnect()]; + if (this.sentinelClient) { + const reply = this.sentinelClient.disconnect(); + promises.push(reply.then(() => {})); } + return Promise.all(promises).then(() => {}); + } } - diff --git a/src/clients/single.ts b/src/clients/single.ts index 2899080..d01d300 100644 --- a/src/clients/single.ts +++ b/src/clients/single.ts @@ -1,165 +1,171 @@ import { Client } from "./client"; import { ConstraintType, EntityType } from "../graph"; -import { RedisCommandArgument, RedisFunctions, RedisScripts } from "@redis/client/dist/lib/commands"; +import { + RedisCommandArgument, + RedisFunctions, + RedisScripts, +} from "@redis/client/dist/lib/commands"; import commands, { QueryOptions } from "../commands"; import { RedisClientType } from "@redis/client"; import FalkorDB from "../falkordb"; -export type SingleGraphConnection = RedisClientType<{ falkordb: typeof commands }, RedisFunctions, RedisScripts>; +export type SingleGraphConnection = RedisClientType< + { falkordb: typeof commands }, + RedisFunctions, + RedisScripts +>; export class Single implements Client { - - protected client: SingleGraphConnection; - #usePool: boolean; - - constructor(client: SingleGraphConnection) { - this.client = client; - this.#usePool = !!(this.client.options?.isolationPoolOptions); - } - - init(falkordb: FalkorDB) { - return Promise.resolve(); - } - - async query(graph: string, query: RedisCommandArgument, options?: QueryOptions, compact=true) { - - const reply = this.#usePool ? - await this.client.executeIsolated(async isolatedClient => { - return isolatedClient.falkordb.query( - graph, - query, - options, - compact - ) - }) - : - await this.client.falkordb.query( - graph, - query, - options, - compact - ); - - return reply; - } - - async roQuery(graph: string, query: RedisCommandArgument, options?: QueryOptions, compact=true) { - const reply = this.#usePool ? - await this.client.executeIsolated(async isolatedClient => { - return isolatedClient.falkordb.roQuery( - graph, - query, - options, - compact - ) - }) - : - await this.client.falkordb.roQuery( - graph, - query, - options, - compact - ); - - return reply; - } - - async delete(graph: string) { - if (this.#usePool) { - return this.client.executeIsolated(async isolatedClient => { - const reply = isolatedClient.falkordb.delete(graph) - return reply.then(() => {}) - }) - } - const reply = this.client.falkordb.delete(graph) - return reply.then(() => {}) - } - - async explain(graph: string, query: string) { - if (this.#usePool) { - return this.client.executeIsolated(async isolatedClient => { - return isolatedClient.falkordb.explain( - graph, - query - ) - }) - } - return this.client.falkordb.explain( - graph, - query - ) - } - - async profile(graph: string, query: string) { - if (this.#usePool) { - - return this.client.executeIsolated(async isolatedClient => { - return isolatedClient.falkordb.profile( graph, query) - }) - } - return this.client.falkordb.profile( graph, query) - } - - async list() { - return this.client.falkordb.list() + protected client: SingleGraphConnection; + #usePool: boolean; + + constructor(client: SingleGraphConnection) { + this.client = client; + this.#usePool = !!this.client.options?.isolationPoolOptions; + } + + init(falkordb: FalkorDB) { + return Promise.resolve(); + } + + async query( + graph: string, + query: RedisCommandArgument, + options?: QueryOptions, + compact = true + ) { + const reply = this.#usePool + ? await this.client.executeIsolated(async (isolatedClient) => { + return isolatedClient.falkordb.query(graph, query, options, compact); + }) + : await this.client.falkordb.query(graph, query, options, compact); + + return reply; + } + + async roQuery( + graph: string, + query: RedisCommandArgument, + options?: QueryOptions, + compact = true + ) { + const reply = this.#usePool + ? await this.client.executeIsolated(async (isolatedClient) => { + return isolatedClient.falkordb.roQuery( + graph, + query, + options, + compact + ); + }) + : await this.client.falkordb.roQuery(graph, query, options, compact); + + return reply; + } + + async delete(graph: string) { + if (this.#usePool) { + return this.client.executeIsolated(async (isolatedClient) => { + const reply = isolatedClient.falkordb.delete(graph); + return reply.then(() => {}); + }); } - - async configGet(configKey: string) { - return this.client.falkordb.configGet(configKey) + const reply = this.client.falkordb.delete(graph); + return reply.then(() => {}); + } + + async explain(graph: string, query: string) { + if (this.#usePool) { + return this.client.executeIsolated(async (isolatedClient) => { + return isolatedClient.falkordb.explain(graph, query); + }); } - - async configSet(configKey: string, value: number | string) { - const reply = this.client.falkordb.configSet(configKey, value) - return reply.then(() => {}) + return this.client.falkordb.explain(graph, query); + } + + async profile(graph: string, query: string) { + if (this.#usePool) { + return this.client.executeIsolated(async (isolatedClient) => { + return isolatedClient.falkordb.profile(graph, query); + }); } - - async info(section?: string) { - return this.client.falkordb.info(section) + return this.client.falkordb.profile(graph, query); + } + + async list() { + return this.client.falkordb.list(); + } + + async configGet(configKey: string) { + return this.client.falkordb.configGet(configKey); + } + + async configSet(configKey: string, value: number | string) { + const reply = this.client.falkordb.configSet(configKey, value); + return reply.then(() => {}); + } + + async info(section?: string) { + return this.client.falkordb.info(section); + } + + async slowLog(graph: string) { + if (this.#usePool) { + return this.client.executeIsolated(async (isolatedClient) => { + return isolatedClient.falkordb.slowLog(graph); + }); } - - async slowLog(graph: string) { - if (this.#usePool) { - return this.client.executeIsolated(async isolatedClient => { - return isolatedClient.falkordb.slowLog( graph) - }) - } - return this.client.falkordb.slowLog(graph) - } - - async constraintCreate(graph: string, constraintType: ConstraintType, entityType: EntityType, - label: string, ...properties: string[]) { - const reply = this.client.falkordb.constraintCreate( - graph, - constraintType, - entityType, - label, - ...properties - ) - return reply.then(() => {}) - } - - async constraintDrop(graph: string, constraintType: ConstraintType, entityType: EntityType, - label: string, ...properties: string[]) { - const reply = this.client.falkordb.constraintDrop( - graph, - constraintType, - entityType, - label, - ...properties - ) - return reply.then(() => {}) - } - - async copy(srcGraph: string, destGraph: string) { - return this.client.falkordb.copy(srcGraph, destGraph) - } - - async quit() { - const reply = this.client.quit(); - return reply.then(() => {}) - } - - async getConnection(){ - return this.client; - } -} \ No newline at end of file + return this.client.falkordb.slowLog(graph); + } + + async constraintCreate( + graph: string, + constraintType: ConstraintType, + entityType: EntityType, + label: string, + ...properties: string[] + ) { + const reply = this.client.falkordb.constraintCreate( + graph, + constraintType, + entityType, + label, + ...properties + ); + return reply.then(() => {}); + } + + async constraintDrop( + graph: string, + constraintType: ConstraintType, + entityType: EntityType, + label: string, + ...properties: string[] + ) { + const reply = this.client.falkordb.constraintDrop( + graph, + constraintType, + entityType, + label, + ...properties + ); + return reply.then(() => {}); + } + + async copy(srcGraph: string, destGraph: string) { + return this.client.falkordb.copy(srcGraph, destGraph); + } + + quit() { + return this.disconnect(); + } + + async disconnect(): Promise { + const reply = this.client.disconnect(); + return reply.then(() => {}); + } + + async getConnection() { + return this.client; + } +} diff --git a/src/falkordb.ts b/src/falkordb.ts index 39ef3e6..c71be34 100644 --- a/src/falkordb.ts +++ b/src/falkordb.ts @@ -188,6 +188,6 @@ export default class FalkorDB extends EventEmitter { * Closes the client. */ async close() { - return this.#client.quit(); + return this.#client.disconnect(); } } From 2f81d0477d622c8c17dab3f3cd2c06cf4a22d4cb Mon Sep 17 00:00:00 2001 From: Dudi Zimberknopf Date: Sun, 1 Dec 2024 11:07:25 +0200 Subject: [PATCH 2/2] bump version 6.2.5 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 85dc2ea..610911a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "falkordb", - "version": "6.2.4", + "version": "6.2.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "falkordb", - "version": "6.2.4", + "version": "6.2.5", "license": "MIT", "workspaces": [ "./packages/*" diff --git a/package.json b/package.json index 98ca626..392f951 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "falkordb", - "version": "6.2.4", + "version": "6.2.5", "description": "A FalkorDB javascript library", "license": "MIT", "main": "./dist/index.js",