UNPKG

eizen

Version:

Vector database Engine for ArchiveNET

1,365 lines (1,358 loc) 66.2 kB
import { createRequire } from "node:module"; import { SetSDK } from "hollowdb"; import { ArweaveSigner } from "warp-contracts-plugin-deploy"; import { Heap } from "heap-js"; //#region rolldown:runtime var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") for (var keys$1 = __getOwnPropNames(from), i = 0, n = keys$1.length, key; i < n; i++) { key = keys$1[i]; if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); var __require = /* @__PURE__ */ createRequire(import.meta.url); //#endregion //#region proto/hnsw_comm.js var require_hnsw_comm = __commonJS({ "proto/hnsw_comm.js"(exports, module) { var $protobuf = __require("protobufjs/minimal"); var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); $root.index_buffer = function() { /** * Namespace index_buffer. * @exports index_buffer * @namespace */ var index_buffer$1 = {}; index_buffer$1.LayerNode = function() { /** * Properties of a LayerNode. * @memberof index_buffer * @interface ILayerNode * @property {number|null} [level] LayerNode level * @property {number|null} [idx] LayerNode idx * @property {boolean|null} [visible] LayerNode visible * @property {Object.<string,number>|null} [neighbors] LayerNode neighbors */ /** * Constructs a new LayerNode. * @memberof index_buffer * @classdesc Represents a LayerNode. * @implements ILayerNode * @constructor * @param {index_buffer.ILayerNode=} [properties] Properties to set */ function LayerNode(properties) { this.neighbors = {}; if (properties) { for (var keys$1 = Object.keys(properties), i = 0; i < keys$1.length; ++i) if (properties[keys$1[i]] != null) this[keys$1[i]] = properties[keys$1[i]]; } } /** * LayerNode level. * @member {number} level * @memberof index_buffer.LayerNode * @instance */ LayerNode.prototype.level = 0; /** * LayerNode idx. * @member {number} idx * @memberof index_buffer.LayerNode * @instance */ LayerNode.prototype.idx = 0; /** * LayerNode visible. * @member {boolean} visible * @memberof index_buffer.LayerNode * @instance */ LayerNode.prototype.visible = false; /** * LayerNode neighbors. * @member {Object.<string,number>} neighbors * @memberof index_buffer.LayerNode * @instance */ LayerNode.prototype.neighbors = $util.emptyObject; /** * Creates a new LayerNode instance using the specified properties. * @function create * @memberof index_buffer.LayerNode * @static * @param {index_buffer.ILayerNode=} [properties] Properties to set * @returns {index_buffer.LayerNode} LayerNode instance */ LayerNode.create = function create(properties) { return new LayerNode(properties); }; /** * Encodes the specified LayerNode message. Does not implicitly {@link index_buffer.LayerNode.verify|verify} messages. * @function encode * @memberof index_buffer.LayerNode * @static * @param {index_buffer.ILayerNode} message LayerNode message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ LayerNode.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); if (message.level != null && Object.hasOwnProperty.call(message, "level")) writer.uint32(8).uint32(message.level); if (message.idx != null && Object.hasOwnProperty.call(message, "idx")) writer.uint32(16).uint32(message.idx); if (message.visible != null && Object.hasOwnProperty.call(message, "visible")) writer.uint32(24).bool(message.visible); if (message.neighbors != null && Object.hasOwnProperty.call(message, "neighbors")) for (var keys$1 = Object.keys(message.neighbors), i = 0; i < keys$1.length; ++i) writer.uint32(34).fork().uint32(8).uint32(keys$1[i]).uint32(21).float(message.neighbors[keys$1[i]]).ldelim(); return writer; }; /** * Encodes the specified LayerNode message, length delimited. Does not implicitly {@link index_buffer.LayerNode.verify|verify} messages. * @function encodeDelimited * @memberof index_buffer.LayerNode * @static * @param {index_buffer.ILayerNode} message LayerNode message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ LayerNode.encodeDelimited = function encodeDelimited(message, writer) { return this.encode(message, writer).ldelim(); }; /** * Decodes a LayerNode message from the specified reader or buffer. * @function decode * @memberof index_buffer.LayerNode * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @param {number} [length] Message length if known beforehand * @returns {index_buffer.LayerNode} LayerNode * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ LayerNode.decode = function decode(reader, length) { if (!(reader instanceof $Reader)) reader = $Reader.create(reader); var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.index_buffer.LayerNode(), key, value; while (reader.pos < end) { var tag = reader.uint32(); switch (tag >>> 3) { case 1: { message.level = reader.uint32(); break; } case 2: { message.idx = reader.uint32(); break; } case 3: { message.visible = reader.bool(); break; } case 4: { if (message.neighbors === $util.emptyObject) message.neighbors = {}; var end2 = reader.uint32() + reader.pos; key = 0; value = 0; while (reader.pos < end2) { var tag2 = reader.uint32(); switch (tag2 >>> 3) { case 1: key = reader.uint32(); break; case 2: value = reader.float(); break; default: reader.skipType(tag2 & 7); break; } } message.neighbors[key] = value; break; } default: reader.skipType(tag & 7); break; } } return message; }; /** * Decodes a LayerNode message from the specified reader or buffer, length delimited. * @function decodeDelimited * @memberof index_buffer.LayerNode * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @returns {index_buffer.LayerNode} LayerNode * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ LayerNode.decodeDelimited = function decodeDelimited(reader) { if (!(reader instanceof $Reader)) reader = new $Reader(reader); return this.decode(reader, reader.uint32()); }; /** * Verifies a LayerNode message. * @function verify * @memberof index_buffer.LayerNode * @static * @param {Object.<string,*>} message Plain object to verify * @returns {string|null} `null` if valid, otherwise the reason why it is not */ LayerNode.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; if (message.level != null && message.hasOwnProperty("level")) { if (!$util.isInteger(message.level)) return "level: integer expected"; } if (message.idx != null && message.hasOwnProperty("idx")) { if (!$util.isInteger(message.idx)) return "idx: integer expected"; } if (message.visible != null && message.hasOwnProperty("visible")) { if (typeof message.visible !== "boolean") return "visible: boolean expected"; } if (message.neighbors != null && message.hasOwnProperty("neighbors")) { if (!$util.isObject(message.neighbors)) return "neighbors: object expected"; var key = Object.keys(message.neighbors); for (var i = 0; i < key.length; ++i) { if (!$util.key32Re.test(key[i])) return "neighbors: integer key{k:uint32} expected"; if (typeof message.neighbors[key[i]] !== "number") return "neighbors: number{k:uint32} expected"; } } return null; }; /** * Creates a LayerNode message from a plain object. Also converts values to their respective internal types. * @function fromObject * @memberof index_buffer.LayerNode * @static * @param {Object.<string,*>} object Plain object * @returns {index_buffer.LayerNode} LayerNode */ LayerNode.fromObject = function fromObject(object) { if (object instanceof $root.index_buffer.LayerNode) return object; var message = new $root.index_buffer.LayerNode(); if (object.level != null) message.level = object.level >>> 0; if (object.idx != null) message.idx = object.idx >>> 0; if (object.visible != null) message.visible = Boolean(object.visible); if (object.neighbors) { if (typeof object.neighbors !== "object") throw TypeError(".index_buffer.LayerNode.neighbors: object expected"); message.neighbors = {}; for (var keys$1 = Object.keys(object.neighbors), i = 0; i < keys$1.length; ++i) message.neighbors[keys$1[i]] = Number(object.neighbors[keys$1[i]]); } return message; }; /** * Creates a plain object from a LayerNode message. Also converts values to other types if specified. * @function toObject * @memberof index_buffer.LayerNode * @static * @param {index_buffer.LayerNode} message LayerNode * @param {$protobuf.IConversionOptions} [options] Conversion options * @returns {Object.<string,*>} Plain object */ LayerNode.toObject = function toObject(message, options) { if (!options) options = {}; var object = {}; if (options.objects || options.defaults) object.neighbors = {}; if (options.defaults) { object.level = 0; object.idx = 0; object.visible = false; } if (message.level != null && message.hasOwnProperty("level")) object.level = message.level; if (message.idx != null && message.hasOwnProperty("idx")) object.idx = message.idx; if (message.visible != null && message.hasOwnProperty("visible")) object.visible = message.visible; var keys2; if (message.neighbors && (keys2 = Object.keys(message.neighbors)).length) { object.neighbors = {}; for (var j = 0; j < keys2.length; ++j) object.neighbors[keys2[j]] = options.json && !isFinite(message.neighbors[keys2[j]]) ? String(message.neighbors[keys2[j]]) : message.neighbors[keys2[j]]; } return object; }; /** * Converts this LayerNode to JSON. * @function toJSON * @memberof index_buffer.LayerNode * @instance * @returns {Object.<string,*>} JSON object */ LayerNode.prototype.toJSON = function toJSON() { return this.constructor.toObject(this, $protobuf.util.toJSONOptions); }; /** * Gets the default type url for LayerNode * @function getTypeUrl * @memberof index_buffer.LayerNode * @static * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") * @returns {string} The default type url */ LayerNode.getTypeUrl = function getTypeUrl(typeUrlPrefix) { if (typeUrlPrefix === void 0) typeUrlPrefix = "type.googleapis.com"; return typeUrlPrefix + "/index_buffer.LayerNode"; }; return LayerNode; }(); index_buffer$1.Point = function() { /** * Properties of a Point. * @memberof index_buffer * @interface IPoint * @property {number|null} [idx] Point idx * @property {Array.<number>|null} [v] Point v */ /** * Constructs a new Point. * @memberof index_buffer * @classdesc Represents a Point. * @implements IPoint * @constructor * @param {index_buffer.IPoint=} [properties] Properties to set */ function Point(properties) { this.v = []; if (properties) { for (var keys$1 = Object.keys(properties), i = 0; i < keys$1.length; ++i) if (properties[keys$1[i]] != null) this[keys$1[i]] = properties[keys$1[i]]; } } /** * Point idx. * @member {number} idx * @memberof index_buffer.Point * @instance */ Point.prototype.idx = 0; /** * Point v. * @member {Array.<number>} v * @memberof index_buffer.Point * @instance */ Point.prototype.v = $util.emptyArray; /** * Creates a new Point instance using the specified properties. * @function create * @memberof index_buffer.Point * @static * @param {index_buffer.IPoint=} [properties] Properties to set * @returns {index_buffer.Point} Point instance */ Point.create = function create(properties) { return new Point(properties); }; /** * Encodes the specified Point message. Does not implicitly {@link index_buffer.Point.verify|verify} messages. * @function encode * @memberof index_buffer.Point * @static * @param {index_buffer.IPoint} message Point message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ Point.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); if (message.idx != null && Object.hasOwnProperty.call(message, "idx")) writer.uint32(8).uint32(message.idx); if (message.v != null && message.v.length) { writer.uint32(18).fork(); for (var i = 0; i < message.v.length; ++i) writer.float(message.v[i]); writer.ldelim(); } return writer; }; /** * Encodes the specified Point message, length delimited. Does not implicitly {@link index_buffer.Point.verify|verify} messages. * @function encodeDelimited * @memberof index_buffer.Point * @static * @param {index_buffer.IPoint} message Point message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ Point.encodeDelimited = function encodeDelimited(message, writer) { return this.encode(message, writer).ldelim(); }; /** * Decodes a Point message from the specified reader or buffer. * @function decode * @memberof index_buffer.Point * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @param {number} [length] Message length if known beforehand * @returns {index_buffer.Point} Point * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ Point.decode = function decode(reader, length) { if (!(reader instanceof $Reader)) reader = $Reader.create(reader); var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.index_buffer.Point(); while (reader.pos < end) { var tag = reader.uint32(); switch (tag >>> 3) { case 1: { message.idx = reader.uint32(); break; } case 2: { if (!(message.v && message.v.length)) message.v = []; if ((tag & 7) === 2) { var end2 = reader.uint32() + reader.pos; while (reader.pos < end2) message.v.push(reader.float()); } else message.v.push(reader.float()); break; } default: reader.skipType(tag & 7); break; } } return message; }; /** * Decodes a Point message from the specified reader or buffer, length delimited. * @function decodeDelimited * @memberof index_buffer.Point * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @returns {index_buffer.Point} Point * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ Point.decodeDelimited = function decodeDelimited(reader) { if (!(reader instanceof $Reader)) reader = new $Reader(reader); return this.decode(reader, reader.uint32()); }; /** * Verifies a Point message. * @function verify * @memberof index_buffer.Point * @static * @param {Object.<string,*>} message Plain object to verify * @returns {string|null} `null` if valid, otherwise the reason why it is not */ Point.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; if (message.idx != null && message.hasOwnProperty("idx")) { if (!$util.isInteger(message.idx)) return "idx: integer expected"; } if (message.v != null && message.hasOwnProperty("v")) { if (!Array.isArray(message.v)) return "v: array expected"; for (var i = 0; i < message.v.length; ++i) if (typeof message.v[i] !== "number") return "v: number[] expected"; } return null; }; /** * Creates a Point message from a plain object. Also converts values to their respective internal types. * @function fromObject * @memberof index_buffer.Point * @static * @param {Object.<string,*>} object Plain object * @returns {index_buffer.Point} Point */ Point.fromObject = function fromObject(object) { if (object instanceof $root.index_buffer.Point) return object; var message = new $root.index_buffer.Point(); if (object.idx != null) message.idx = object.idx >>> 0; if (object.v) { if (!Array.isArray(object.v)) throw TypeError(".index_buffer.Point.v: array expected"); message.v = []; for (var i = 0; i < object.v.length; ++i) message.v[i] = Number(object.v[i]); } return message; }; /** * Creates a plain object from a Point message. Also converts values to other types if specified. * @function toObject * @memberof index_buffer.Point * @static * @param {index_buffer.Point} message Point * @param {$protobuf.IConversionOptions} [options] Conversion options * @returns {Object.<string,*>} Plain object */ Point.toObject = function toObject(message, options) { if (!options) options = {}; var object = {}; if (options.arrays || options.defaults) object.v = []; if (options.defaults) object.idx = 0; if (message.idx != null && message.hasOwnProperty("idx")) object.idx = message.idx; if (message.v && message.v.length) { object.v = []; for (var j = 0; j < message.v.length; ++j) object.v[j] = options.json && !isFinite(message.v[j]) ? String(message.v[j]) : message.v[j]; } return object; }; /** * Converts this Point to JSON. * @function toJSON * @memberof index_buffer.Point * @instance * @returns {Object.<string,*>} JSON object */ Point.prototype.toJSON = function toJSON() { return this.constructor.toObject(this, $protobuf.util.toJSONOptions); }; /** * Gets the default type url for Point * @function getTypeUrl * @memberof index_buffer.Point * @static * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") * @returns {string} The default type url */ Point.getTypeUrl = function getTypeUrl(typeUrlPrefix) { if (typeUrlPrefix === void 0) typeUrlPrefix = "type.googleapis.com"; return typeUrlPrefix + "/index_buffer.Point"; }; return Point; }(); index_buffer$1.PointQuant = function() { /** * Properties of a PointQuant. * @memberof index_buffer * @interface IPointQuant * @property {number|null} [idx] PointQuant idx * @property {Array.<number>|null} [v] PointQuant v */ /** * Constructs a new PointQuant. * @memberof index_buffer * @classdesc Represents a PointQuant. * @implements IPointQuant * @constructor * @param {index_buffer.IPointQuant=} [properties] Properties to set */ function PointQuant(properties) { this.v = []; if (properties) { for (var keys$1 = Object.keys(properties), i = 0; i < keys$1.length; ++i) if (properties[keys$1[i]] != null) this[keys$1[i]] = properties[keys$1[i]]; } } /** * PointQuant idx. * @member {number} idx * @memberof index_buffer.PointQuant * @instance */ PointQuant.prototype.idx = 0; /** * PointQuant v. * @member {Array.<number>} v * @memberof index_buffer.PointQuant * @instance */ PointQuant.prototype.v = $util.emptyArray; /** * Creates a new PointQuant instance using the specified properties. * @function create * @memberof index_buffer.PointQuant * @static * @param {index_buffer.IPointQuant=} [properties] Properties to set * @returns {index_buffer.PointQuant} PointQuant instance */ PointQuant.create = function create(properties) { return new PointQuant(properties); }; /** * Encodes the specified PointQuant message. Does not implicitly {@link index_buffer.PointQuant.verify|verify} messages. * @function encode * @memberof index_buffer.PointQuant * @static * @param {index_buffer.IPointQuant} message PointQuant message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ PointQuant.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); if (message.idx != null && Object.hasOwnProperty.call(message, "idx")) writer.uint32(8).uint32(message.idx); if (message.v != null && message.v.length) { writer.uint32(18).fork(); for (var i = 0; i < message.v.length; ++i) writer.uint32(message.v[i]); writer.ldelim(); } return writer; }; /** * Encodes the specified PointQuant message, length delimited. Does not implicitly {@link index_buffer.PointQuant.verify|verify} messages. * @function encodeDelimited * @memberof index_buffer.PointQuant * @static * @param {index_buffer.IPointQuant} message PointQuant message or plain object to encode * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ PointQuant.encodeDelimited = function encodeDelimited(message, writer) { return this.encode(message, writer).ldelim(); }; /** * Decodes a PointQuant message from the specified reader or buffer. * @function decode * @memberof index_buffer.PointQuant * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @param {number} [length] Message length if known beforehand * @returns {index_buffer.PointQuant} PointQuant * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ PointQuant.decode = function decode(reader, length) { if (!(reader instanceof $Reader)) reader = $Reader.create(reader); var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.index_buffer.PointQuant(); while (reader.pos < end) { var tag = reader.uint32(); switch (tag >>> 3) { case 1: { message.idx = reader.uint32(); break; } case 2: { if (!(message.v && message.v.length)) message.v = []; if ((tag & 7) === 2) { var end2 = reader.uint32() + reader.pos; while (reader.pos < end2) message.v.push(reader.uint32()); } else message.v.push(reader.uint32()); break; } default: reader.skipType(tag & 7); break; } } return message; }; /** * Decodes a PointQuant message from the specified reader or buffer, length delimited. * @function decodeDelimited * @memberof index_buffer.PointQuant * @static * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from * @returns {index_buffer.PointQuant} PointQuant * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ PointQuant.decodeDelimited = function decodeDelimited(reader) { if (!(reader instanceof $Reader)) reader = new $Reader(reader); return this.decode(reader, reader.uint32()); }; /** * Verifies a PointQuant message. * @function verify * @memberof index_buffer.PointQuant * @static * @param {Object.<string,*>} message Plain object to verify * @returns {string|null} `null` if valid, otherwise the reason why it is not */ PointQuant.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; if (message.idx != null && message.hasOwnProperty("idx")) { if (!$util.isInteger(message.idx)) return "idx: integer expected"; } if (message.v != null && message.hasOwnProperty("v")) { if (!Array.isArray(message.v)) return "v: array expected"; for (var i = 0; i < message.v.length; ++i) if (!$util.isInteger(message.v[i])) return "v: integer[] expected"; } return null; }; /** * Creates a PointQuant message from a plain object. Also converts values to their respective internal types. * @function fromObject * @memberof index_buffer.PointQuant * @static * @param {Object.<string,*>} object Plain object * @returns {index_buffer.PointQuant} PointQuant */ PointQuant.fromObject = function fromObject(object) { if (object instanceof $root.index_buffer.PointQuant) return object; var message = new $root.index_buffer.PointQuant(); if (object.idx != null) message.idx = object.idx >>> 0; if (object.v) { if (!Array.isArray(object.v)) throw TypeError(".index_buffer.PointQuant.v: array expected"); message.v = []; for (var i = 0; i < object.v.length; ++i) message.v[i] = object.v[i] >>> 0; } return message; }; /** * Creates a plain object from a PointQuant message. Also converts values to other types if specified. * @function toObject * @memberof index_buffer.PointQuant * @static * @param {index_buffer.PointQuant} message PointQuant * @param {$protobuf.IConversionOptions} [options] Conversion options * @returns {Object.<string,*>} Plain object */ PointQuant.toObject = function toObject(message, options) { if (!options) options = {}; var object = {}; if (options.arrays || options.defaults) object.v = []; if (options.defaults) object.idx = 0; if (message.idx != null && message.hasOwnProperty("idx")) object.idx = message.idx; if (message.v && message.v.length) { object.v = []; for (var j = 0; j < message.v.length; ++j) object.v[j] = message.v[j]; } return object; }; /** * Converts this PointQuant to JSON. * @function toJSON * @memberof index_buffer.PointQuant * @instance * @returns {Object.<string,*>} JSON object */ PointQuant.prototype.toJSON = function toJSON() { return this.constructor.toObject(this, $protobuf.util.toJSONOptions); }; /** * Gets the default type url for PointQuant * @function getTypeUrl * @memberof index_buffer.PointQuant * @static * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") * @returns {string} The default type url */ PointQuant.getTypeUrl = function getTypeUrl(typeUrlPrefix) { if (typeUrlPrefix === void 0) typeUrlPrefix = "type.googleapis.com"; return typeUrlPrefix + "/index_buffer.PointQuant"; }; return PointQuant; }(); return index_buffer$1; }(); module.exports = $root; } }); //#endregion //#region src/codec.ts var import_hnsw_comm = __toESM(require_hnsw_comm()); /** Encodes a point to protobuf & base64's it. */ function encodePoint(q) { const qe = import_hnsw_comm.index_buffer.Point.encode(q).finish(); return Buffer.from(qe).toString("base64"); } /** Decodes a point from base64 encoded protobuf. */ function decodePoint(data) { const dec = Buffer.from(data, "base64"); return import_hnsw_comm.index_buffer.Point.decode(dec); } /** Encodes a layerNode to protobuf & base64's it. */ function encodeLayerNode(n) { const ne = import_hnsw_comm.index_buffer.LayerNode.encode({ ...n, visible: n.visible || true }).finish(); return Buffer.from(ne).toString("base64"); } /** Decodes a layerNode from base64 encoded protobuf. */ function decodeLayerNode(data) { const dec = Buffer.from(data, "base64"); return import_hnsw_comm.index_buffer.LayerNode.decode(dec); } //#endregion //#region src/db/common/index.ts /** KVdb key generators for different data types */ const keys = { layers: "layers", ep: "ep", points: "points", metadata: (idx) => `m:${idx}`, point: (idx) => `${idx}`, neighbor: (layer, idx) => `${layer}__${idx}` }; /** Parse JSON string, returns null for falsy values */ function safeParse(data) { return data ? JSON.parse(data) : null; } //#endregion //#region src/db/index.ts /** * EizenMemory - A distributed memory implementation for vector similarity search * * This class provides a hierarchical navigation structure for approximate nearest neighbor search. * It uses layered graphs where higher layers contain fewer, more connected nodes for efficient search. * * Key concepts: * - Points: Vector data stored with unique indices * - Layers: Hierarchical levels of the graph structure * - Neighbors: Connected nodes in each layer forming the searchable graph * - Entry Point (EP): Starting node for search operations * * @template M - Type for optional metadata associated with points */ var EizenMemory = class { client; /** * Deploy a new contract for this database instance * * @param initialState - Initial state configuration for the contract * @param source - ( Optional) source transaction ID for contract deployment * @returns The deployed contract transaction ID */ async deploy(initialState, source = "") { const { contractTxId } = await this.client.warp.deployFromSourceTx({ wallet: this.client.signer, srcTxId: source, initState: JSON.stringify(initialState) }); return contractTxId; } constructor(client) { this.client = client; } /** * Get the current entry point index for search operations * The entry point is the starting node for navigating the graph structure */ async get_ep() { const ep = await this.client.get(keys.ep); return ep === null ? null : Number.parseInt(ep); } /** * Set the entry point for search operations * Should typically be a well-connected node in the highest layer */ async set_ep(ep) { await this.client.set(keys.ep, ep.toString()); } /** * Retrieve a single point (vector) by its index * * @param idx - Unique identifier for the point * @returns The point data * @throws Error if point doesn't exist or has no value */ async get_point(idx) { const data = await this.client.get(keys.point(idx)); if (!data) throw new Error(`No point with index ${idx}`); const point = decodePoint(data); if (!point.v) throw new Error(`Point at index ${idx} has no value`); return point.v; } /** * Retrieve multiple points in a single operation for better performance * * @param idxs - Array of point indices to retrieve * @returns Array of points in the same order as input indices * @throws Error if any point is missing or invalid */ async get_points(idxs) { if (idxs.length === 0) return []; const datas = await this.safe_get_many(idxs.map((idx) => keys.point(idx))); const nullPos = datas.indexOf(null); if (nullPos !== -1) throw new Error(`No point with index ${idxs[nullPos]}`); const points = datas.map((data, i) => { if (data === null) throw new Error(`No data for point at index ${idxs[i]}`); return decodePoint(data); }); return points.map((point, i) => { if (!point.v) throw new Error(`Point at index ${idxs[i]} has no value`); return point.v; }); } /** * Add a new point to the database and assign it the next available index * * @param q - Point data to store * @returns The assigned index for this point */ async new_point(q) { const idx = await this.get_datasize(); const point = encodePoint({ v: q, idx }); await this.client.set(keys.point(idx), point); await this.client.set(keys.points, (idx + 1).toString()); return idx; } /** * Get the total number of layers in the hierarchical structure * Higher layers have fewer, more connected nodes for efficient search */ async get_num_layers() { const numLayers = await this.client.get(keys.layers); return numLayers ? Number.parseInt(numLayers) : 0; } /** * Get the total number of points stored in the database * This represents the next available index for new points */ async get_datasize() { const datasize = await this.client.get(keys.points); return datasize ? Number.parseInt(datasize) : 0; } /** * Get the neighbor connections for a specific node in a specific layer * * @param layer - Layer level (0 = base layer, higher = more sparse) * @param idx - Node index within that layer * @returns The neighbor connections for this node * @throws Error if node doesn't exist or has no neighbors */ async get_neighbor(layer, idx) { const data = await this.client.get(keys.neighbor(layer, idx)); if (!data) throw new Error(`No neighbors at layer ${layer}, index ${idx}"`); const node = decodeLayerNode(data); if (!node.neighbors) throw new Error(`Node at layer ${layer}, index ${idx} has no neighbors`); return node.neighbors; } /** * Get neighbor connections for multiple nodes in a layer (batch operation) * * @param layer - Layer level to query * @param idxs - Array of node indices to retrieve * @returns Graph object mapping node indices to their neighbor lists * @throws Error if any node is missing or invalid */ async get_neighbors(layer, idxs) { const datas = await this.safe_get_many(idxs.map((idx) => keys.neighbor(layer, idx))); const nullPos = datas.indexOf(null); if (nullPos !== -1) throw new Error(`No neighbors at layer ${layer}, index ${idxs[nullPos]}"`); const nodes = datas.map((data, i) => { if (data === null) throw new Error(`No data for neighbor at layer ${layer}, index ${idxs[i]}`); return decodeLayerNode(data); }); const neighbors = nodes.map((node, i) => { if (!node.neighbors) throw new Error(`Node at layer ${layer}, index ${idxs[i]} has no neighbors`); return node.neighbors; }); return Object.fromEntries(idxs.map((idx, i) => [idx, neighbors[i]])); } /** * Create or update neighbor connections for a single node * * @param layer - Layer level where the node exists * @param idx - Node index to update * @param node - New neighbor connections for this node */ async upsert_neighbor(layer, idx, node) { const data = encodeLayerNode({ idx, level: layer, neighbors: node }); await this.client.set(keys.neighbor(layer, idx), data); } /** * Batch update neighbor connections for multiple nodes in a layer * More efficient than individual upsert operations for bulk updates * * @param layer - Layer level to update * @param nodes - Graph mapping node indices to their new neighbor connections */ async upsert_neighbors(layer, nodes) { await this.safe_set_many(Object.keys(nodes).map((idx) => { const i = Number.parseInt(idx); const key = keys.neighbor(layer, i); const value = encodeLayerNode({ idx: i, level: layer, neighbors: nodes[i] }); return [key, value]; })); } /** * Initialize a new layer and add a node with empty neighbors * This creates a new level in the hierarchical structure * * WARNING: Concurrent calls may cause race conditions in layer counting * * @param idx - Index of the node to add to the new layer */ async new_neighbor(idx) { const l = await this.get_num_layers(); await this.upsert_neighbor(l, idx, {}); await this.client.set(keys.layers, (l + 1).toString()); } /** * Retrieve optional metadata associated with a point * * @param idx - Point index * @returns Metadata object or null if none exists */ async get_metadata(idx) { const data = await this.client.get(keys.metadata(idx)); return safeParse(data); } /** * Retrieve metadata for multiple points * Returns null for points that have no metadata * * @param idxs - Array of point indices * @returns Array of metadata objects (or null) in same order as input */ async get_metadatas(idxs) { return Promise.all(idxs.map((idx) => this.get_metadata(idx))); } /** * Store metadata for a specific point * * @param idx - Point index * @param data - Metadata to associate with this point */ async set_metadata(idx, data) { await this.client.set(keys.metadata(idx), JSON.stringify(data)); } /** * Safely retrieve multiple keys with automatic request splitting * * Base-DB has transaction size limits. This method automatically splits * large requests into smaller chunks when the limit is exceeded. * Uses recursive binary splitting on errors. */ async safe_get_many(keys$1) { try { return await this.client.getMany(keys$1); } catch (err) { const half = Math.floor(keys$1.length >> 1); return await Promise.all([this.safe_get_many(keys$1.slice(0, half)), this.safe_get_many(keys$1.slice(half))]).then((results) => results.flat()); } } /** * Safely set multiple key-value pairs with automatic request splitting * * Similar to safe_get_many, this handles transaction size limits by * recursively splitting large batches into smaller ones. */ async safe_set_many(entries) { try { await this.client.setMany(entries.map((e) => e[0]), entries.map((e) => e[1])); } catch (err) { const half = Math.floor(entries.length >> 1); await Promise.all([this.safe_set_many(entries.slice(0, half)), this.safe_set_many(entries.slice(half))]).then((results) => results.flat()); } } toString() { return "yay, EizenDB Set with Protobufs"; } }; //#endregion //#region src/utils/index.ts /** * HNSW Utility Functions * ===================== * * This module provides utility functions and data structures used by the HNSW algorithm, * including distance functions, heap data structures, and vector operations. */ /** * A specialized min-heap for Node types used in HNSW search algorithms. * * This heap automatically sorts nodes by their distance values (first element of the tuple). * It's used extensively in the search algorithms to maintain candidate lists and results. * * @example * ```typescript * const heap = new NodeHeap(); * heap.push([0.5, 10]); // Distance 0.5 to point 10 * heap.push([0.2, 5]); // Distance 0.2 to point 5 * * const closest = heap.pop(); // Returns [0.2, 5] (smallest distance) * ``` */ var NodeHeap = class extends Heap { constructor(elems = []) { super(compareNode); if (elems.length !== 0) super.addAll(elems); } }; /** * Comparator function for Node types that compares by distance. * * Used by the NodeHeap to maintain proper ordering. Compares the first element * of the Node tuple (the distance value). * * @param a First node to compare * @param b Second node to compare * @returns Negative if a < b, positive if a > b, zero if equal */ function compareNode(a, b) { return a[0] - b[0]; } /** * Computes the dot product (inner product) of two vectors. * * The dot product measures the cosine of the angle between vectors scaled by their magnitudes. * It's a fundamental operation used in many distance calculations. * * @param a First vector * @param b Second vector * @returns The dot product (sum of element-wise products) * * @example * ```typescript * const a = [1, 2, 3]; * const b = [4, 5, 6]; * const result = dot_product(a, b); // 1*4 + 2*5 + 3*6 = 32 * ``` */ function dot_product(a, b) { return a.reduce((sum, val, idx) => sum + val * b[idx], 0); } /** * Computes the Euclidean norm (magnitude) of a vector. * * The norm represents the length of the vector in Euclidean space. * It's used in cosine distance calculations and vector normalization. * * @param a The vector to compute the norm for * @returns The Euclidean norm (square root of sum of squared elements) * * @example * ```typescript * const vector = [3, 4]; * const magnitude = norm(vector); // sqrt(3² + 4²) = 5 * ``` */ function norm(a) { return Math.sqrt(a.reduce((sum, val) => sum + val * val, 0)); } /** * Computes the cosine distance between two vectors. * * Cosine distance is defined as 1 - cosine_similarity, where cosine similarity * is the dot product of normalized vectors. This distance measure is particularly * useful for high-dimensional data as it focuses on the angle between vectors * rather than their magnitudes. * * Range: [0, 2] where: * - 0 = vectors point in same direction (most similar) * - 1 = vectors are orthogonal (no correlation) * - 2 = vectors point in opposite directions (most dissimilar) * * @param a First vector * @param b Second vector * @returns The cosine distance between the vectors * * @example * ```typescript * const doc1 = [1, 2, 0]; // Document embedding * const doc2 = [2, 4, 0]; // Very similar document (same direction) * const doc3 = [-1, -2, 0]; // Opposite document * * cosine_distance(doc1, doc2); // ≈ 0 (very similar) * cosine_distance(doc1, doc3); // ≈ 2 (very different) * ``` */ function cosine_distance(a, b) { return 1 - dot_product(a, b) / (norm(a) * norm(b)); } //#endregion //#region src/hnsw.ts /** * Hierarchical Navigable Small Worlds (HNSW) Implementation * * HNSW is a graph-based algorithm for approximate nearest neighbor search in high-dimensional spaces. * It builds a multi-layer graph structure where: * - Layer 0 contains all points and forms the base layer * - Higher layers contain progressively fewer points (sampled probabilistically) * - Each layer maintains connections between nearby points * * Key Concepts: * - **Multi-layer structure**: Higher layers enable long-range navigation, lower layers provide precision * - **Entry point**: A single node in the top layer that serves as the starting point for all searches * - **Greedy search**: Navigate by always moving to the closest unvisited neighbor * - **Layer selection**: New points are assigned to layers using an exponential decay probability * * Algorithm Benefits: * - Logarithmic search complexity: O(log N) for both search and insertion * - High recall: Can find very good approximate nearest neighbors * - Scalable: Works well with millions of high-dimensional vectors * * This implementation works over a key-value database interface, allowing different storage backends. * * @template M Type of the metadata attached to each point (e.g., document IDs, labels, etc.) * * @see https://arxiv.org/pdf/1603.09320.pdf Original HNSW paper by Malkov & Yashunin */ var HNSW = class { /** Database interface for storing points, graph connections, and metadata */ db; /** * Maximum number of bi-directional links for each node during construction. * This parameter controls the connectivity of the graph: * - Higher values = better search quality but slower construction and more memory * - Lower values = faster construction but potentially worse search quality * - Paper suggests m ∈ [5, 48], with 16 being a good default * - Weaviate uses 64 for high-dimensional data */ m; /** * Maximum number of connections for layer 0 (base layer). * Set to 2 * m as recommended in the paper. * Layer 0 can have more connections since it contains all points. */ m_max0; /** * Normalization factor for level generation probability. * Used in the exponential decay formula: level = floor(-ln(uniform(0,1)) * ml) * Set to 1/ln(m) as per the paper's heuristic. */ ml; /** * Size of the dynamic candidate list during construction. * Controls the search scope when finding neighbors for new points: * - Higher values = better graph quality but slower construction * - Lower values = faster construction but potentially worse search quality * - Common values: 40 (fast), 100 (balanced), 400 (high quality) */ ef_construction; /** * Size of the dynamic candidate list during search. * Controls the search scope when performing kNN queries: * - Higher values = better recall but slower search * - Lower values = faster search but potentially lower recall * - Should be >= k (number of neighbors to return) * - Can be adjusted at search time for different speed/quality tradeoffs */ ef; /** * Constructs a new HNSW index with the specified parameters. * * @param db Database interface for persistence (must implement DBInterface) * @param M Maximum number of connections per node (recommended: 16, range: [5-48]) * @param ef_construction Size of candidate list during construction (recommended: 200) * @param ef_search Size of candidate list during search (recommended: 50, must be >= k) * * @example * ```typescript * const hnsw = new HNSW( * database, // Your database implementation * 16, // M: good balance of speed/quality * 200, // ef_construction: high quality graph * 50 // ef_search: good search performance * ); * ``` */ constructor(db, M, ef_construction, ef_search) { this.db = db; this.m = M; this.m_max0 = M * 2; this.ml = 1 / Math.log(M); this.ef_construction = ef_construction; this.ef = ef_search; } /** * Retrieves a vector and its associated metadata by index. * * This is a convenience method that fetches both the vector data and any * metadata stored with it in a single operation. * * @param idx The index of the vector to retrieve * @returns Object containing the vector data and metadata (null if no metadata exists) * * @example * ```typescript * const result = await hnsw.get_vector(42); * console.log('Vector:', result.point); // [0.1, 0.2, 0.3, ...] * console.log('Metadata:', result.metadata); // { filename: 'doc.pdf', category: 'research' } * ``` */ async get_vector(idx) { const point = await this.db.get_point(idx); const metadata = await this.db.get_metadata(idx); return { point, metadata }; } /** * Selects which layer a new point should be inserted into. * * Uses an exponential decay probability distribution as recommended in the paper. * Most points will be inserted into layer 0, with progressively fewer points * in higher layers. This creates the hierarchical structure that makes HNSW efficient. * * The probability of a point being in layer L or higher is: (1/2)^L * This means: * - ~50% of points are only in layer 0 * - ~25% of points reach layer 1 or higher * - ~12.5% of points reach layer 2 or higher * - etc. * * @returns The layer number (0-based) where the new point should be inserted * * @example * ```typescript * const layer = hnsw.select_layer(); // Returns 0, 1, 2, 3, ... with decreasing probability * ``` */ select_layer() { return Math.floor(-Math.log(Math.random()) * this.ml); } /** * Inserts a new point into the HNSW index. * * This is the core method that implements Algorithm 1 from the HNSW paper. * The insertion process works in several phases: * * 1. **Layer Selection**: Randomly determine which layer the new point belongs to * 2. **Entry Point Search**: Navigate from top layer down to find the best entry point * 3. **Layer-by-layer Insertion**: Insert the point into each layer from selected layer down to 0 * 4. **Neighbor Selection**: For each layer, find the best neighbors and create bidirectional links * 5. **Pruning**: Ensure no node has too many connections by removing the worst ones * * Time Complexity: O(log N) expected, where N is the number of points * Space Complexity: O(M * N) where M is the average number of connections per point * * @param q The vector to insert (array of numbers representing the point in space) * @param metadata Optional metadata to associate with this point (e.g., document ID, labels) * * @example * ```typescript * // Insert a simple vector * await hnsw.insert([0.1, 0.2, 0.3, 0.4]); * * // Insert a vector with metadata * await hnsw.insert( * [0.1, 0.2, 0.3, 0.4], * { filename: 'document.pdf', category: 'research' } * ); * ``` * * @see https://arxiv.org/pdf/1603.09320.pdf Algorithm 1 (page 7) */ async insert(q, metadata) { const ep_index = await this.db.get_ep(); const L = await this.db.get_num_layers() - 1; const l = this.select_layer(); const idx = await this.db.new_point(q); if (metadata) await this.db.set_metadata(idx, metadata); if (ep_index !== null) { const dist = cosine_distance(q, await this.db.get_point(ep_index)); let ep = [[dist, ep_index]]; for (let i = L; i > l; i--) { const ep_copy = ep.map((e) => [e[0], e[1]]); const W = await this.search_layer(q, ep_copy, 1, i); if (W.length > 0 && ep[0][0] > W[0][0]) ep = W; } for (let l_c = Math.min(L, l); l_c >= 0; l_c--) { const W = await this.search_layer(q, ep, this.ef_construction, l_c); const newNode = {}; ep = W.map((e) => [e[0], e[1]]); const neighbors = this.select_neighbors(q, W, l_c); const indices = neighbors.map(([, idx$1]) => idx$1); const nodes = await this.db.get_neighbors(l_c, indices); const M = l_c === 0 ? this.m_max0 : this.m; for (const e of neighbors) { newNode[e[1]] = e[0]; nodes[e[1]][idx] = e[0]; } for (const e of neighbors) { const eConn = Object.entries(nodes[e[1]]).map(([k, v]) => [v, Number.parseInt(k)]); if (eConn.length > M) { const eNewConn = this.select_neighbors(await this.db.get_point(e[1]), eConn, l_c); const dict = {}; for (const eNew of eNewConn) dict[eNew[1]] = eNew[0]; nodes[e[