@harperfast/harper 5.0.0-alpha.10 → 5.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (446) hide show
  1. package/bin/BinObjects.js +17 -0
  2. package/bin/cliOperations.js +157 -0
  3. package/bin/copyDb.ts +280 -0
  4. package/bin/harper.js +156 -0
  5. package/bin/install.js +15 -0
  6. package/bin/lite.js +5 -0
  7. package/bin/restart.js +201 -0
  8. package/bin/run.js +409 -0
  9. package/bin/status.js +65 -0
  10. package/bin/stop.js +22 -0
  11. package/bin/upgrade.js +134 -0
  12. package/components/Application.ts +646 -0
  13. package/components/ApplicationScope.ts +49 -0
  14. package/components/Component.ts +53 -0
  15. package/components/ComponentV1.ts +342 -0
  16. package/components/DEFAULT_CONFIG.ts +18 -0
  17. package/components/EntryHandler.ts +227 -0
  18. package/components/Logger.ts +14 -0
  19. package/components/OptionsWatcher.ts +354 -0
  20. package/components/PluginModule.ts +6 -0
  21. package/components/Scope.ts +329 -0
  22. package/components/componentLoader.ts +529 -0
  23. package/components/deriveCommonPatternBase.ts +31 -0
  24. package/components/deriveGlobOptions.ts +44 -0
  25. package/components/deriveURLPath.ts +57 -0
  26. package/components/operations.js +658 -0
  27. package/components/operationsValidation.js +246 -0
  28. package/components/packageComponent.ts +39 -0
  29. package/components/requestRestart.ts +26 -0
  30. package/components/resolveBaseURLPath.ts +38 -0
  31. package/components/status/ComponentStatus.ts +110 -0
  32. package/components/status/ComponentStatusRegistry.ts +251 -0
  33. package/components/status/api.ts +153 -0
  34. package/components/status/crossThread.ts +405 -0
  35. package/components/status/errors.ts +152 -0
  36. package/components/status/index.ts +44 -0
  37. package/components/status/internal.ts +65 -0
  38. package/components/status/registry.ts +12 -0
  39. package/components/status/types.ts +96 -0
  40. package/config/RootConfigWatcher.ts +59 -0
  41. package/config/configHelpers.ts +11 -0
  42. package/config/configUtils.js +967 -0
  43. package/config/harperConfigEnvVars.ts +641 -0
  44. package/dataLayer/CreateAttributeObject.js +25 -0
  45. package/dataLayer/CreateTableObject.js +11 -0
  46. package/dataLayer/DataLayerObjects.js +43 -0
  47. package/dataLayer/DeleteBeforeObject.js +22 -0
  48. package/dataLayer/DeleteObject.js +25 -0
  49. package/dataLayer/DropAttributeObject.js +11 -0
  50. package/dataLayer/GetBackupObject.js +22 -0
  51. package/dataLayer/InsertObject.js +24 -0
  52. package/dataLayer/ReadAuditLogObject.js +24 -0
  53. package/dataLayer/SQLSearch.js +1335 -0
  54. package/dataLayer/SearchByConditionsObject.js +61 -0
  55. package/dataLayer/SearchByHashObject.js +21 -0
  56. package/dataLayer/SearchObject.js +45 -0
  57. package/dataLayer/SqlSearchObject.js +14 -0
  58. package/dataLayer/UpdateObject.js +23 -0
  59. package/dataLayer/UpsertObject.js +23 -0
  60. package/dataLayer/bulkLoad.js +813 -0
  61. package/dataLayer/dataObjects/BulkLoadObjects.js +27 -0
  62. package/dataLayer/dataObjects/UpsertObject.js +23 -0
  63. package/dataLayer/delete.js +164 -0
  64. package/dataLayer/export.js +381 -0
  65. package/dataLayer/getBackup.js +40 -0
  66. package/dataLayer/harperBridge/BridgeMethods.js +81 -0
  67. package/dataLayer/harperBridge/ResourceBridge.ts +633 -0
  68. package/dataLayer/harperBridge/bridgeUtility/insertUpdateReturnObj.js +28 -0
  69. package/dataLayer/harperBridge/bridgeUtility/insertUpdateValidate.js +88 -0
  70. package/dataLayer/harperBridge/harperBridge.js +21 -0
  71. package/dataLayer/harperBridge/lmdbBridge/LMDBBridge.js +119 -0
  72. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +19 -0
  73. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js +112 -0
  74. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js +67 -0
  75. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js +31 -0
  76. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js +94 -0
  77. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js +98 -0
  78. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteRecords.js +89 -0
  79. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js +109 -0
  80. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js +107 -0
  81. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js +137 -0
  82. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbFlush.js +35 -0
  83. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetBackup.js +111 -0
  84. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByHash.js +28 -0
  85. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js +29 -0
  86. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbReadAuditLog.js +207 -0
  87. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js +156 -0
  88. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByHash.js +21 -0
  89. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js +30 -0
  90. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbTransaction.js +19 -0
  91. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpdateRecords.js +64 -0
  92. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js +70 -0
  93. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js +22 -0
  94. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBDeleteTransactionObject.js +23 -0
  95. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBInsertTransactionObject.js +22 -0
  96. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBTransactionObject.js +23 -0
  97. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpdateTransactionObject.js +24 -0
  98. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpsertTransactionObject.js +24 -0
  99. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js +25 -0
  100. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js +21 -0
  101. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +157 -0
  102. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js +94 -0
  103. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js +39 -0
  104. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +34 -0
  105. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js +100 -0
  106. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbSearch.js +371 -0
  107. package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbWriteTransaction.js +109 -0
  108. package/dataLayer/hdbInfoController.js +254 -0
  109. package/dataLayer/insert.js +266 -0
  110. package/dataLayer/readAuditLog.js +59 -0
  111. package/dataLayer/schema.js +366 -0
  112. package/dataLayer/schemaDescribe.js +289 -0
  113. package/dataLayer/search.js +60 -0
  114. package/dataLayer/transaction.js +17 -0
  115. package/dataLayer/update.js +124 -0
  116. package/dist/components/Logger.d.ts +12 -0
  117. package/dist/{resources/ResourceInterfaceV2.js → components/Logger.js} +1 -1
  118. package/dist/components/Logger.js.map +1 -0
  119. package/dist/components/Scope.d.ts +14 -4
  120. package/dist/components/Scope.js +18 -10
  121. package/dist/components/Scope.js.map +1 -1
  122. package/dist/components/componentLoader.js +17 -10
  123. package/dist/components/componentLoader.js.map +1 -1
  124. package/dist/components/operations.js +2 -2
  125. package/dist/components/operations.js.map +1 -1
  126. package/dist/config/configUtils.d.ts +1 -1
  127. package/dist/config/configUtils.js +1 -1
  128. package/dist/config/configUtils.js.map +1 -1
  129. package/dist/dataLayer/CreateTableObject.d.ts +2 -2
  130. package/dist/dataLayer/CreateTableObject.js +2 -2
  131. package/dist/dataLayer/CreateTableObject.js.map +1 -1
  132. package/dist/dataLayer/delete.d.ts +1 -1
  133. package/dist/dataLayer/schema.js +6 -5
  134. package/dist/dataLayer/schema.js.map +1 -1
  135. package/dist/dataLayer/schemaDescribe.js +1 -1
  136. package/dist/dataLayer/schemaDescribe.js.map +1 -1
  137. package/dist/index.d.ts +1 -1
  138. package/dist/index.js +2 -0
  139. package/dist/index.js.map +1 -1
  140. package/dist/resources/DatabaseTransaction.d.ts +1 -1
  141. package/dist/resources/IterableEventQueue.d.ts +1 -1
  142. package/dist/resources/LMDBTransaction.d.ts +5 -1
  143. package/dist/resources/Resource.d.ts +1 -1
  144. package/dist/resources/ResourceInterface.d.ts +1 -1
  145. package/dist/resources/RocksIndexStore.d.ts +3 -3
  146. package/dist/resources/RocksTransactionLogStore.d.ts +6 -3
  147. package/dist/resources/Table.d.ts +15 -6
  148. package/dist/resources/Table.js +12 -4
  149. package/dist/resources/Table.js.map +1 -1
  150. package/dist/resources/analytics/read.js +32 -22
  151. package/dist/resources/analytics/read.js.map +1 -1
  152. package/dist/resources/analytics/write.js +3 -6
  153. package/dist/resources/analytics/write.js.map +1 -1
  154. package/dist/resources/auditStore.d.ts +3 -3
  155. package/dist/resources/blob.d.ts +25 -2
  156. package/dist/resources/databases.d.ts +12 -2
  157. package/dist/resources/databases.js +22 -19
  158. package/dist/resources/databases.js.map +1 -1
  159. package/dist/resources/search.js +11 -5
  160. package/dist/resources/search.js.map +1 -1
  161. package/dist/resources/transaction.d.ts +2 -1
  162. package/dist/security/auth.js +1 -1
  163. package/dist/security/auth.js.map +1 -1
  164. package/dist/security/cryptoHash.d.ts +2 -2
  165. package/dist/security/jsLoader.js +265 -73
  166. package/dist/security/jsLoader.js.map +1 -1
  167. package/dist/security/keys.js +11 -12
  168. package/dist/security/keys.js.map +1 -1
  169. package/dist/security/user.js +3 -3
  170. package/dist/security/user.js.map +1 -1
  171. package/dist/server/REST.js +16 -2
  172. package/dist/server/REST.js.map +1 -1
  173. package/dist/server/Server.d.ts +2 -1
  174. package/dist/server/Server.js.map +1 -1
  175. package/dist/server/fastifyRoutes/plugins/hdbCore.d.ts +6 -1
  176. package/dist/server/fastifyRoutes.js +2 -0
  177. package/dist/server/fastifyRoutes.js.map +1 -1
  178. package/dist/server/http.js +12 -6
  179. package/dist/server/http.js.map +1 -1
  180. package/dist/server/jobs/JobObject.d.ts +3 -3
  181. package/dist/server/loadRootComponents.js +1 -0
  182. package/dist/server/loadRootComponents.js.map +1 -1
  183. package/dist/server/operationsServer.js +3 -1
  184. package/dist/server/operationsServer.js.map +1 -1
  185. package/dist/server/serverHelpers/JSONStream.d.ts +3 -3
  186. package/dist/server/serverHelpers/Request.d.ts +5 -5
  187. package/dist/server/serverHelpers/requestTimePlugin.d.ts +1 -1
  188. package/dist/server/threads/manageThreads.d.ts +2 -2
  189. package/dist/server/threads/manageThreads.js +52 -35
  190. package/dist/server/threads/manageThreads.js.map +1 -1
  191. package/dist/server/threads/socketRouter.d.ts +1 -1
  192. package/dist/sqlTranslator/deleteTranslator.d.ts +1 -1
  193. package/dist/utility/AWS/AWSConnector.d.ts +3 -2
  194. package/dist/utility/common_utils.d.ts +3 -3
  195. package/dist/utility/environment/systemInformation.d.ts +1 -0
  196. package/dist/utility/functions/date/dateFunctions.d.ts +11 -11
  197. package/dist/utility/globalSchema.d.ts +1 -1
  198. package/dist/utility/hdbTerms.d.ts +3 -0
  199. package/dist/utility/hdbTerms.js +3 -0
  200. package/dist/utility/hdbTerms.js.map +1 -1
  201. package/dist/utility/installation.d.ts +2 -4
  202. package/dist/utility/installation.js.map +1 -1
  203. package/dist/utility/lmdb/commonUtility.d.ts +2 -1
  204. package/dist/utility/lmdb/commonUtility.js +20 -13
  205. package/dist/utility/lmdb/commonUtility.js.map +1 -1
  206. package/dist/utility/lmdb/deleteUtility.d.ts +1 -0
  207. package/dist/utility/lmdb/environmentUtility.d.ts +1 -0
  208. package/dist/utility/lmdb/searchUtility.d.ts +2 -1
  209. package/dist/utility/lmdb/writeUtility.d.ts +1 -0
  210. package/dist/utility/logging/harper_logger.d.ts +6 -6
  211. package/dist/utility/processManagement/processManagement.d.ts +1 -1
  212. package/dist/utility/processManagement/servicesConfig.d.ts +12 -6
  213. package/dist/validation/common_validators.d.ts +4 -3
  214. package/dist/validation/configValidator.d.ts +3 -2
  215. package/index.d.ts +56 -0
  216. package/index.js +41 -0
  217. package/json/systemSchema.json +373 -0
  218. package/launchServiceScripts/launchHarperDB.js +3 -0
  219. package/launchServiceScripts/utility/checkNodeVersion.js +15 -0
  220. package/package.json +35 -16
  221. package/resources/DatabaseTransaction.ts +378 -0
  222. package/resources/ErrorResource.ts +57 -0
  223. package/resources/IterableEventQueue.ts +94 -0
  224. package/resources/LMDBTransaction.ts +349 -0
  225. package/resources/RecordEncoder.ts +702 -0
  226. package/resources/RequestTarget.ts +134 -0
  227. package/resources/Resource.ts +789 -0
  228. package/resources/ResourceInterface.ts +221 -0
  229. package/resources/Resources.ts +162 -0
  230. package/resources/RocksIndexStore.ts +70 -0
  231. package/resources/RocksTransactionLogStore.ts +352 -0
  232. package/resources/Table.ts +4531 -0
  233. package/resources/analytics/hostnames.ts +72 -0
  234. package/resources/analytics/metadata.ts +10 -0
  235. package/resources/analytics/read.ts +252 -0
  236. package/resources/analytics/write.ts +803 -0
  237. package/resources/auditStore.ts +556 -0
  238. package/resources/blob.ts +1268 -0
  239. package/resources/crdt.ts +125 -0
  240. package/resources/dataLoader.ts +527 -0
  241. package/resources/databases.ts +1290 -0
  242. package/resources/graphql.ts +221 -0
  243. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +638 -0
  244. package/resources/indexes/customIndexes.ts +7 -0
  245. package/resources/indexes/vector.ts +38 -0
  246. package/resources/jsResource.ts +86 -0
  247. package/resources/loadEnv.ts +22 -0
  248. package/resources/login.ts +18 -0
  249. package/resources/openApi.ts +409 -0
  250. package/resources/registrationDeprecated.ts +8 -0
  251. package/resources/replayLogs.ts +136 -0
  252. package/resources/roles.ts +98 -0
  253. package/resources/search.ts +1301 -0
  254. package/resources/tracked.ts +584 -0
  255. package/resources/transaction.ts +89 -0
  256. package/resources/transactionBroadcast.ts +258 -0
  257. package/security/auth.ts +376 -0
  258. package/security/certificateVerification/certificateVerificationSource.ts +84 -0
  259. package/security/certificateVerification/configValidation.ts +107 -0
  260. package/security/certificateVerification/crlVerification.ts +623 -0
  261. package/security/certificateVerification/index.ts +121 -0
  262. package/security/certificateVerification/ocspVerification.ts +148 -0
  263. package/security/certificateVerification/pkijs-ed25519-patch.ts +188 -0
  264. package/security/certificateVerification/types.ts +128 -0
  265. package/security/certificateVerification/verificationConfig.ts +138 -0
  266. package/security/certificateVerification/verificationUtils.ts +447 -0
  267. package/security/cryptoHash.js +42 -0
  268. package/security/data_objects/PermissionAttributeResponseObject.js +15 -0
  269. package/security/data_objects/PermissionResponseObject.js +115 -0
  270. package/security/data_objects/PermissionTableResponseObject.js +20 -0
  271. package/security/fastifyAuth.js +169 -0
  272. package/security/impersonation.ts +160 -0
  273. package/security/jsLoader.ts +733 -0
  274. package/security/keys.js +948 -0
  275. package/security/permissionsTranslator.js +300 -0
  276. package/security/role.js +218 -0
  277. package/security/tokenAuthentication.ts +228 -0
  278. package/security/user.ts +449 -0
  279. package/server/DurableSubscriptionsSession.ts +503 -0
  280. package/server/REST.ts +407 -0
  281. package/server/Server.ts +89 -0
  282. package/server/fastifyRoutes/helpers/getCORSOptions.js +36 -0
  283. package/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +15 -0
  284. package/server/fastifyRoutes/helpers/getServerOptions.js +33 -0
  285. package/server/fastifyRoutes/plugins/hdbCore.js +39 -0
  286. package/server/fastifyRoutes.ts +205 -0
  287. package/server/graphqlQuerying.ts +700 -0
  288. package/server/http.ts +640 -0
  289. package/server/itc/serverHandlers.js +161 -0
  290. package/server/itc/utility/ITCEventObject.js +10 -0
  291. package/server/jobs/JobObject.js +24 -0
  292. package/server/jobs/jobProcess.js +69 -0
  293. package/server/jobs/jobRunner.js +162 -0
  294. package/server/jobs/jobs.js +304 -0
  295. package/server/loadRootComponents.js +44 -0
  296. package/server/mqtt.ts +485 -0
  297. package/server/nodeName.ts +75 -0
  298. package/server/operationsServer.ts +313 -0
  299. package/server/serverHelpers/Headers.ts +108 -0
  300. package/server/serverHelpers/JSONStream.ts +269 -0
  301. package/server/serverHelpers/OperationFunctionObject.ts +13 -0
  302. package/server/serverHelpers/Request.ts +158 -0
  303. package/server/serverHelpers/contentTypes.ts +637 -0
  304. package/server/serverHelpers/requestTimePlugin.js +57 -0
  305. package/server/serverHelpers/serverHandlers.js +148 -0
  306. package/server/serverHelpers/serverUtilities.ts +473 -0
  307. package/server/serverRegistry.ts +8 -0
  308. package/server/static.ts +187 -0
  309. package/server/status/definitions.ts +37 -0
  310. package/server/status/index.ts +125 -0
  311. package/server/storageReclamation.ts +93 -0
  312. package/server/threads/itc.js +89 -0
  313. package/server/threads/manageThreads.js +596 -0
  314. package/server/threads/socketRouter.ts +360 -0
  315. package/server/threads/threadServer.js +279 -0
  316. package/server/throttle.ts +73 -0
  317. package/sqlTranslator/SelectValidator.js +330 -0
  318. package/sqlTranslator/alasqlFunctionImporter.js +62 -0
  319. package/sqlTranslator/deleteTranslator.js +67 -0
  320. package/sqlTranslator/index.js +242 -0
  321. package/sqlTranslator/sql_statement_bucket.js +472 -0
  322. package/static/defaultConfig.yaml +3 -0
  323. package/studio/web/HDBDogOnly.svg +78 -0
  324. package/studio/web/assets/PPRadioGrotesk-Bold-DDaUYG8E.woff +0 -0
  325. package/studio/web/assets/fa-brands-400-CEJbCg16.woff +0 -0
  326. package/studio/web/assets/fa-brands-400-CSYNqBb_.ttf +0 -0
  327. package/studio/web/assets/fa-brands-400-DnkPfk3o.eot +0 -0
  328. package/studio/web/assets/fa-brands-400-UxlILjvJ.woff2 +0 -0
  329. package/studio/web/assets/fa-brands-400-cH1MgKbP.svg +3717 -0
  330. package/studio/web/assets/fa-regular-400-BhTwtT8w.eot +0 -0
  331. package/studio/web/assets/fa-regular-400-D1vz6WBx.ttf +0 -0
  332. package/studio/web/assets/fa-regular-400-DFnMcJPd.woff +0 -0
  333. package/studio/web/assets/fa-regular-400-DGzu1beS.woff2 +0 -0
  334. package/studio/web/assets/fa-regular-400-gwj8Pxq-.svg +801 -0
  335. package/studio/web/assets/fa-solid-900-B4ZZ7kfP.svg +5034 -0
  336. package/studio/web/assets/fa-solid-900-B6Axprfb.eot +0 -0
  337. package/studio/web/assets/fa-solid-900-BUswJgRo.woff2 +0 -0
  338. package/studio/web/assets/fa-solid-900-DOXgCApm.woff +0 -0
  339. package/studio/web/assets/fa-solid-900-mxuxnBEa.ttf +0 -0
  340. package/studio/web/assets/index-C1G-Jo6n.js +37 -0
  341. package/studio/web/assets/index-C1G-Jo6n.js.map +1 -0
  342. package/studio/web/assets/index-D-CahN0-.js +2 -0
  343. package/studio/web/assets/index-D-CahN0-.js.map +1 -0
  344. package/studio/web/assets/index-DxlZI0PX.js +235 -0
  345. package/studio/web/assets/index-DxlZI0PX.js.map +1 -0
  346. package/studio/web/assets/index-Y2g_iFpU.css +1 -0
  347. package/studio/web/assets/index-jiPwkrsB.css +1 -0
  348. package/studio/web/assets/index.lazy-BUXDDqq9.js +266 -0
  349. package/studio/web/assets/index.lazy-BUXDDqq9.js.map +1 -0
  350. package/studio/web/assets/profiler-CU93QiSW.js +2 -0
  351. package/studio/web/assets/profiler-CU93QiSW.js.map +1 -0
  352. package/studio/web/assets/react-redux-B8k9Ep7e.js +6 -0
  353. package/studio/web/assets/react-redux-B8k9Ep7e.js.map +1 -0
  354. package/studio/web/assets/startRecording-DFeBXGk6.js +3 -0
  355. package/studio/web/assets/startRecording-DFeBXGk6.js.map +1 -0
  356. package/studio/web/fabric-signup-background.webp +0 -0
  357. package/studio/web/fabric-signup-text.png +0 -0
  358. package/studio/web/favicon_purple.png +0 -0
  359. package/studio/web/github-icon.svg +15 -0
  360. package/studio/web/harper-fabric_black.png +0 -0
  361. package/studio/web/harper-fabric_white.png +0 -0
  362. package/studio/web/harper-studio_white.png +0 -0
  363. package/studio/web/index.html +16 -0
  364. package/studio/web/running.css +148 -0
  365. package/studio/web/running.html +147 -0
  366. package/studio/web/running.js +111 -0
  367. package/upgrade/UpgradeObjects.js +13 -0
  368. package/upgrade/directives/directivesController.js +90 -0
  369. package/upgrade/directivesManager.js +139 -0
  370. package/upgrade/upgradePrompt.js +124 -0
  371. package/upgrade/upgradeUtilities.js +28 -0
  372. package/utility/AWS/AWSConnector.js +29 -0
  373. package/utility/OperationFunctionCaller.js +63 -0
  374. package/utility/assignCmdEnvVariables.js +62 -0
  375. package/utility/common_utils.js +867 -0
  376. package/utility/environment/environmentManager.js +208 -0
  377. package/utility/environment/systemInformation.js +355 -0
  378. package/utility/errors/commonErrors.js +267 -0
  379. package/utility/errors/hdbError.js +146 -0
  380. package/utility/functions/date/dateFunctions.js +65 -0
  381. package/utility/functions/geo.js +355 -0
  382. package/utility/functions/sql/alaSQLExtension.js +104 -0
  383. package/utility/globalSchema.js +35 -0
  384. package/utility/hdbTerms.ts +819 -0
  385. package/utility/install/checkJWTTokensExist.js +62 -0
  386. package/utility/install/harperdb.conf +15 -0
  387. package/utility/install/harperdb.service +14 -0
  388. package/utility/install/installer.js +635 -0
  389. package/utility/installation.ts +30 -0
  390. package/utility/lmdb/DBIDefinition.js +20 -0
  391. package/utility/lmdb/DeleteRecordsResponseObject.js +25 -0
  392. package/utility/lmdb/InsertRecordsResponseObject.js +22 -0
  393. package/utility/lmdb/OpenDBIObject.js +31 -0
  394. package/utility/lmdb/OpenEnvironmentObject.js +41 -0
  395. package/utility/lmdb/UpdateRecordsResponseObject.js +25 -0
  396. package/utility/lmdb/UpsertRecordsResponseObject.js +22 -0
  397. package/utility/lmdb/cleanLMDBMap.js +65 -0
  398. package/utility/lmdb/commonUtility.js +130 -0
  399. package/utility/lmdb/deleteUtility.js +128 -0
  400. package/utility/lmdb/environmentUtility.js +477 -0
  401. package/utility/lmdb/searchCursorFunctions.js +187 -0
  402. package/utility/lmdb/searchUtility.js +918 -0
  403. package/utility/lmdb/terms.js +57 -0
  404. package/utility/lmdb/writeUtility.js +407 -0
  405. package/utility/logging/harper_logger.js +876 -0
  406. package/utility/logging/logRotator.js +157 -0
  407. package/utility/logging/logger.ts +24 -0
  408. package/utility/logging/readLog.js +355 -0
  409. package/utility/logging/transactionLog.js +57 -0
  410. package/utility/mount_hdb.js +59 -0
  411. package/utility/npmUtilities.js +102 -0
  412. package/utility/operationPermissions.ts +112 -0
  413. package/utility/operation_authorization.js +836 -0
  414. package/utility/packageUtils.js +55 -0
  415. package/utility/password.ts +99 -0
  416. package/utility/processManagement/processManagement.js +187 -0
  417. package/utility/processManagement/servicesConfig.js +56 -0
  418. package/utility/scripts/restartHdb.js +24 -0
  419. package/utility/scripts/user_data.sh +13 -0
  420. package/utility/signalling.js +36 -0
  421. package/utility/terms/certificates.js +81 -0
  422. package/utility/when.ts +20 -0
  423. package/validation/bulkDeleteValidator.js +24 -0
  424. package/validation/check_permissions.js +19 -0
  425. package/validation/common_validators.js +95 -0
  426. package/validation/configValidator.js +331 -0
  427. package/validation/deleteValidator.js +15 -0
  428. package/validation/fileLoadValidator.js +153 -0
  429. package/validation/insertValidator.js +40 -0
  430. package/validation/installValidator.js +37 -0
  431. package/validation/readLogValidator.js +64 -0
  432. package/validation/role_validation.js +320 -0
  433. package/validation/schemaMetadataValidator.js +42 -0
  434. package/validation/searchValidator.js +166 -0
  435. package/validation/statusValidator.ts +66 -0
  436. package/validation/transactionLogValidator.js +33 -0
  437. package/validation/user_validation.js +55 -0
  438. package/validation/validationWrapper.js +105 -0
  439. package/dist/resources/ResourceInterfaceV2.d.ts +0 -21
  440. package/dist/resources/ResourceInterfaceV2.js.map +0 -1
  441. package/dist/resources/ResourceV2.d.ts +0 -30
  442. package/dist/resources/ResourceV2.js +0 -27
  443. package/dist/resources/ResourceV2.js.map +0 -1
  444. package/dist/resources/analytics/profile.d.ts +0 -2
  445. package/dist/resources/analytics/profile.js +0 -144
  446. package/dist/resources/analytics/profile.js.map +0 -1
@@ -0,0 +1,638 @@
1
+ import { cosineDistance, euclideanDistance } from './vector.ts';
2
+ import { FLOAT32_OPTIONS } from 'msgpackr';
3
+ import { loggerWithTag } from '../../utility/logging/logger.ts';
4
+ import { ClientError } from '../../utility/errors/hdbError.js';
5
+ import type { Id } from '../../resources/ResourceInterface.ts';
6
+
7
+ const logger = loggerWithTag('HNSW');
8
+ /**
9
+ * Implementation of a vector index for Harper, using hierarchical navigable small world graphs.
10
+ */
11
+ const ENTRY_POINT = Symbol.for('entryPoint');
12
+ const KEY_PREFIX = Symbol.for('key');
13
+ const MAX_LEVEL = 10; // should give good high-level skip list performance up to trillions of nodes
14
+ type Connection = {
15
+ id: number;
16
+ distance: number;
17
+ };
18
+ type Node = {
19
+ vector: number[];
20
+ level?: number;
21
+ primaryKey: string;
22
+ [level: number]: Connection[];
23
+ };
24
+ /**
25
+ * Represents a Hierarchical Navigable Small World (HNSW) index for approximate nearest neighbor search.
26
+ * This implementation is based on hierarchical graph navigation to efficiently index and search high-dimensional vectors.
27
+ * A HNSW is basically a multi-dimensional skip list. Each node has (potentially) higher levels that are used for quickly
28
+ * traversing the graph get in the neighborhood of the node, and then lower levels are used to more accurately find the
29
+ * closest neighbors.
30
+ *
31
+ * This implementation is based on the paper "Efficient and Robust Approximate Nearest Neighbor Search in High Dimensions"
32
+ * (mostly influenced AI's contributions)
33
+ */
34
+ export class HierarchicalNavigableSmallWorld {
35
+ static useObjectStore = true;
36
+ indexStore: any;
37
+ M: number = 16; // max number of connections per layer
38
+ efConstruction: number = 100; // size of dynamic candidate list
39
+ efConstructionSearch: number = 50; // size of dynamic candidate list for search
40
+ mL: number = 1 / Math.log(this.M); // normalization factor for level generation
41
+ // how aggressive do we avoid connections that have alternate indirect routes; a value of 0 never avoids connections,
42
+ // a value of 1 is extremely aggressive.
43
+ optimizeRouting = 0.5;
44
+ nodesVisitedCount = 0;
45
+
46
+ idIncrementer: BigInt64Array | undefined;
47
+ distance: (a: number[], b: number[]) => number;
48
+ constructor(indexStore: any, options: any) {
49
+ this.indexStore = indexStore;
50
+ if (indexStore) {
51
+ // use float32 representation of numbers as it is twice as space efficient as typical float64 and plenty accurate
52
+ // (we would actually like to use float16 if it were available)
53
+ this.indexStore.encoder.useFloat32 = FLOAT32_OPTIONS.ALWAYS;
54
+ }
55
+ this.distance = options?.distance === 'euclidean' ? euclideanDistance : cosineDistance;
56
+ if (options) {
57
+ // allow all the HNSW parameters to be configured/tuned
58
+ if (options.M !== undefined) {
59
+ this.M = options.M;
60
+ this.mL = 1 / Math.log(this.M); // recalculate
61
+ }
62
+ if (options.efConstruction !== undefined)
63
+ this.efConstruction = this.efConstructionSearch = options.efConstruction;
64
+ if (options.efConstructionSearch !== undefined) this.efConstructionSearch = options.efConstructionSearch;
65
+ if (options.mL !== undefined) this.mL = options.mL;
66
+ if (options.optimizeRouting !== undefined) this.optimizeRouting = options.optimizeRouting;
67
+ }
68
+ }
69
+ index(primaryKey: Id, vector: number[], existingVector?: number[], options: any = {}) {
70
+ // first get the node id for the primary key; we use internal node ids for better efficiency,
71
+ // but we must use a safe key that won't collide with the node ids
72
+ const safeKey = typeof primaryKey === 'number' ? [KEY_PREFIX, primaryKey] : primaryKey;
73
+ let nodeId = this.indexStore.getSync(safeKey, options);
74
+ // if the node id is not found, create a new node (and store it in the index store)
75
+ // (note that we don't need to check if the node id is already in the index store,
76
+ // because we use internal node ids for better efficiency, and we use a safe key
77
+ // that won't collide with the node ids, so we can't have a collision with internal
78
+ if (!nodeId) {
79
+ if (!vector) return; // didn't exist before, doesn't exist now, nothing to do
80
+ if (!this.idIncrementer) {
81
+ let largestNodeId = 0;
82
+ for (const key of this.indexStore.getKeys({
83
+ reverse: true,
84
+ limit: 1,
85
+ start: Infinity,
86
+ end: 0,
87
+ transaction: options.transaction,
88
+ })) {
89
+ if (typeof key === 'number') largestNodeId = key;
90
+ }
91
+
92
+ this.idIncrementer = new BigInt64Array([BigInt(largestNodeId) + 1n]);
93
+ this.idIncrementer = new BigInt64Array(
94
+ this.indexStore.getUserSharedBuffer('next-id', this.idIncrementer.buffer)
95
+ );
96
+ }
97
+ nodeId = Number(Atomics.add(this.idIncrementer, 0, 1n));
98
+ this.indexStore.put(safeKey, nodeId, options);
99
+ }
100
+ const updatedNodes = new Map<number, Node>();
101
+ let oldNode: Node;
102
+ // If this is the first entry, create it as the entry point
103
+ let entryPointId = this.indexStore.getSync(ENTRY_POINT, options);
104
+ if (existingVector) {
105
+ // If we are updating an existing entry, we need to update the entry point
106
+ // if the new entry is closer to the entry point than the old one
107
+ oldNode = { ...this.indexStore.getSync(nodeId, options) };
108
+ } else oldNode = {} as Node;
109
+ if (vector) {
110
+ let entryPoint = entryPointId && this.indexStore.getSync(entryPointId, options);
111
+ if (entryPoint == null) {
112
+ const level = Math.floor(-Math.log(Math.random()) * this.mL);
113
+ const node = {
114
+ vector,
115
+ level,
116
+ primaryKey,
117
+ };
118
+ for (let i = 0; i <= level; i++) {
119
+ node[i] = [];
120
+ }
121
+ this.indexStore.put(nodeId, node, options);
122
+ if (typeof nodeId !== 'number') {
123
+ throw new Error('Invalid nodeId: ' + nodeId);
124
+ }
125
+ logger.debug?.('setting entry point to', nodeId);
126
+ this.indexStore.put(ENTRY_POINT, nodeId, options);
127
+ return;
128
+ }
129
+
130
+ // Generate random level for this new element
131
+ const level = oldNode.level ?? Math.min(Math.floor(-Math.log(Math.random()) * this.mL), MAX_LEVEL);
132
+ let currentLevel = entryPoint.level;
133
+ if (level >= currentLevel) {
134
+ // if we are at this level or higher, make this the new entry point
135
+ if (typeof nodeId !== 'number') {
136
+ throw new Error('Invalid nodeId: ' + nodeId);
137
+ }
138
+ logger.debug?.('setting entry point to', nodeId);
139
+ this.indexStore.put(ENTRY_POINT, nodeId, options);
140
+ }
141
+
142
+ // For each level from top to bottom
143
+ while (currentLevel > level) {
144
+ // Search for closest neighbors at current level
145
+ const neighbors = this.searchLayer(vector, entryPointId, entryPoint, this.efConstruction, currentLevel);
146
+
147
+ if (neighbors.length > 0) {
148
+ entryPointId = neighbors[0].id; // closest neighbor becomes new entry point
149
+ entryPoint = neighbors[0].node;
150
+ }
151
+ currentLevel--;
152
+ }
153
+ const connections = new Array(level + 1);
154
+ for (let i = 0; i <= level; i++) {
155
+ connections[i] = [];
156
+ }
157
+
158
+ // Connect the new element to neighbors at its level and below
159
+ for (let l = Math.min(level, currentLevel); l >= 0; l--) {
160
+ let neighbors = this.searchLayer(vector, entryPointId, entryPoint, this.efConstruction, l);
161
+ neighbors = neighbors.slice(0, this.M << 1) as SearchResults;
162
+
163
+ if (neighbors.length === 0 && l === 0) {
164
+ logger.info?.('should not have zero connections for', entryPointId);
165
+ }
166
+ const connectionsAtLevel = connections[l];
167
+ // Create bidirectional connections
168
+ for (let i = 0; i < neighbors.length; i++) {
169
+ const { id, distance, node } = neighbors[i];
170
+ if (id === nodeId) continue; // don't connect to self
171
+ const connectionsToBeReplaced: { fromId: number; toId: number }[] = [];
172
+ if (this.optimizeRouting) {
173
+ // if we have existing connections through other nodes, we deprioritize new connections through them.
174
+ // I believe this yields better HNSW graphs, avoiding redundant paths, with better directed connectivity
175
+ // towards desired results
176
+ let skipping = false;
177
+ const neighborNeighbors = node[l];
178
+ const distanceThreshold = 1 + this.optimizeRouting * (1 + (0.5 * i) / this.M);
179
+ for (let i2 = 0; i2 < neighborNeighbors?.length; i2++) {
180
+ const { id: neighborId, distance: neighborDistance } = neighborNeighbors[i2];
181
+ const neighborDistanceThreshold = 1 + this.optimizeRouting * (1 + (0.5 * i2) / this.M);
182
+ for (let i3 = 0; i3 < connectionsAtLevel.length; i3++) {
183
+ const { id: addedId, distance: addedDistance } = connectionsAtLevel[i3];
184
+ if (addedId === neighborId) {
185
+ if (distance * distanceThreshold > addedDistance + neighborDistance) {
186
+ // if the new distance is relatively low compared to existing indirect connections,
187
+ // we skip this neighbor since it is of less value
188
+ skipping = true;
189
+ } else if (neighborDistance * neighborDistanceThreshold > distance + addedDistance) {
190
+ // potentially remove the neighbor's neighbor, because we are adding a better route (if we do add it)
191
+ connectionsToBeReplaced.push({ fromId: addedId, toId: id });
192
+ connectionsToBeReplaced.push({ fromId: id, toId: addedId });
193
+ }
194
+ break;
195
+ }
196
+ }
197
+ if (skipping) break;
198
+ }
199
+ if (skipping) continue;
200
+ } else if (i >= (l > 0 ? this.M : this.M << 1)) {
201
+ // fallback to traditional HNSW level limiting; if we are at the maximum number of neighbors, we skip this one
202
+ continue;
203
+ }
204
+ // Add connection to the new element
205
+ connectionsAtLevel.push({ id, distance });
206
+
207
+ for (const { fromId, toId } of connectionsToBeReplaced) {
208
+ let from = updateNode(fromId);
209
+ if (!from) from = updateNode(fromId, this.indexStore.getSync(fromId, options));
210
+ for (let i = 0; i < from[l].length; i++) {
211
+ if (from[l][i].id === toId) {
212
+ if (Object.isFrozen(from[l])) {
213
+ from[l] = from[l].slice();
214
+ }
215
+ from[l].splice(i, 1);
216
+ break;
217
+ }
218
+ }
219
+ }
220
+
221
+ // Add reverse connection from neighbor to new element if it didn't exist before
222
+ // First check to see if we had an existing neighbor connection before. If we did we can
223
+ // just remove from the list of the connections to remove (don't remove, leave it in place)
224
+ let oldConnections = oldNode[l] as WithCopied;
225
+ const oldConnection = oldConnections?.find(({ id: nid }) => nid === id);
226
+ if (oldConnection) {
227
+ const oldPosition = oldConnections?.indexOf(oldConnection);
228
+ if (!oldConnections.copied) {
229
+ // make a copy, it is likely frozen
230
+ oldConnections = [...oldConnections] as WithCopied;
231
+ oldConnections.copied = true;
232
+ oldNode[l] = oldConnections;
233
+ }
234
+ oldConnections.splice(oldPosition, 1);
235
+ } else {
236
+ // add new connection since this is truly a new connection now
237
+ this.addConnection(id, updateNode(id, node), nodeId, l, distance, updateNode, options);
238
+ }
239
+ }
240
+ }
241
+
242
+ // Store the new element
243
+ this.indexStore.put(
244
+ nodeId,
245
+ {
246
+ vector,
247
+ level,
248
+ primaryKey,
249
+ ...connections,
250
+ },
251
+ options
252
+ );
253
+ } else {
254
+ // removal of this node, but first make sure we have a valid entry point
255
+ if (entryPointId === nodeId) {
256
+ // if this is the entry point, find a new entry point
257
+ const lastLevel = oldNode.level ?? 0;
258
+ for (let l = lastLevel; l >= 0; l--) {
259
+ entryPointId = oldNode[l]?.[0]?.id;
260
+ if (entryPointId !== undefined) break;
261
+ }
262
+ if (entryPointId === undefined) {
263
+ // scan through all nodes to find one with highest level
264
+ let highestLevel = -1;
265
+ for (const { key, value } of this.indexStore.getRange({
266
+ start: 0,
267
+ end: Infinity,
268
+ })) {
269
+ if (value.level > highestLevel) {
270
+ entryPointId = key;
271
+ if (value.level === lastLevel) break; // if we found a node at the same level as the last entry point, we can stop
272
+ highestLevel = value.level;
273
+ }
274
+ }
275
+ }
276
+ if (entryPointId === undefined) {
277
+ // no nodes left in index
278
+ this.indexStore.remove(ENTRY_POINT, options);
279
+ } else {
280
+ // set the new entry point
281
+ if (typeof entryPointId !== 'number') {
282
+ throw new Error('Invalid nodeId: ' + entryPointId);
283
+ }
284
+ logger.debug?.('setting entry point to', entryPointId);
285
+ this.indexStore.put(ENTRY_POINT, entryPointId, options);
286
+ }
287
+ }
288
+ this.indexStore.remove(nodeId, options);
289
+ }
290
+ const needsReindexing = new Map();
291
+ // remove connections to this node that are no longer valid
292
+ if (oldNode.level !== undefined) {
293
+ for (let l = 0; l <= oldNode.level; l++) {
294
+ const oldConnections = oldNode[l];
295
+ for (const { id: neighborId } of oldConnections) {
296
+ // get and copy the neighbor node so we can modify it
297
+ const neighborNode = updateNode(neighborId, this.indexStore.getSync(neighborId, options));
298
+ if (!neighborNode) continue;
299
+ for (let l2 = 0; l2 <= l; l2++) {
300
+ // remove the connection to this node from the neighbor node
301
+ neighborNode[l2] = neighborNode[l2]?.filter(({ id: nid }) => {
302
+ return nid !== nodeId;
303
+ });
304
+ if (neighborNode[l2]?.length === 0) {
305
+ logger.trace?.('node was left orphaned, will reindex', neighborId);
306
+ needsReindexing.set(neighborNode.primaryKey, neighborNode.vector);
307
+ }
308
+ }
309
+ }
310
+ }
311
+ }
312
+ function updateNode(id: number, node?: Node) {
313
+ // keep a record of all our changes, maintaining any changes that are queued to be written
314
+ let updatedNode: Node = updatedNodes.get(id);
315
+ if (!updatedNode && node) {
316
+ // copy the node so we can modify it
317
+ updatedNode = { ...node };
318
+ updatedNodes.set(id, updatedNode);
319
+ }
320
+ return updatedNode;
321
+ }
322
+ for (const [id, updatedNode] of updatedNodes) {
323
+ this.indexStore.put(id, updatedNode, options);
324
+ }
325
+ for (const [key, vector] of needsReindexing) {
326
+ this.index(key, vector, vector);
327
+ }
328
+ this.checkSymmetry(nodeId, this.indexStore.getSync(nodeId, options), options);
329
+ }
330
+
331
+ private getEntryPoint() {
332
+ // Get entry point
333
+ const entryPointId = this.indexStore.getSync(ENTRY_POINT);
334
+ if (entryPointId === undefined) return;
335
+ const node = this.indexStore.getSync(entryPointId);
336
+ return { id: entryPointId, ...node };
337
+ }
338
+
339
+ /**
340
+ * Search one layer of the skip-list using HNSW algorithm for creating a candidate list and navigating the graph
341
+ * TODO: This should be async, but we can't really do that with lmdb-js's transaction system right now. Should be
342
+ * doable with RocksDB. We could also create an async version for searching.
343
+ * @param queryVector
344
+ * @param entryPointId
345
+ * @param entryPoint
346
+ * @param ef
347
+ * @param level
348
+ * @param distanceFunction
349
+ * @private
350
+ */
351
+ private searchLayer(
352
+ queryVector: number[],
353
+ entryPointId: number,
354
+ entryPoint: any,
355
+ ef: number,
356
+ level: number,
357
+ distanceFunction = this.distance
358
+ ): SearchResults {
359
+ const visited = new Set([entryPointId]);
360
+ const candidates = [
361
+ {
362
+ id: entryPointId,
363
+ distance: this.distance(queryVector, entryPoint.vector),
364
+ node: entryPoint,
365
+ },
366
+ ];
367
+ const results = [...candidates] as SearchResults;
368
+
369
+ while (candidates.length > 0) {
370
+ // Get closest unvisited element
371
+ candidates.sort((a, b) => a.distance - b.distance);
372
+ const current = candidates.shift();
373
+
374
+ // Get least result distance
375
+ const furthestDistance = results[results.length - 1].distance;
376
+
377
+ // If current candidate is less similar than our worst result, we're done
378
+ if (current.distance > furthestDistance) break;
379
+
380
+ // Check neighbors of current point
381
+ const currentNode = current.node;
382
+ for (const { id: neighborId } of currentNode[level] || []) {
383
+ if (visited.has(neighborId) || neighborId === undefined) continue;
384
+ visited.add(neighborId);
385
+
386
+ const neighbor = this.indexStore.getSync(neighborId);
387
+ if (!neighbor) continue;
388
+ this.nodesVisitedCount++;
389
+ const distance = distanceFunction(queryVector, neighbor.vector);
390
+
391
+ if (distance < furthestDistance || results.length < ef) {
392
+ const candidate = {
393
+ id: neighborId,
394
+ distance,
395
+ node: neighbor,
396
+ };
397
+ candidates.push(candidate);
398
+ results.push(candidate);
399
+ }
400
+ }
401
+ results.sort((a, b) => a.distance - b.distance);
402
+ if (results.length > ef) results.splice(ef, results.length - ef);
403
+ }
404
+ results.visited = visited.size;
405
+ return results;
406
+ }
407
+
408
+ /**
409
+ * This the main entry from Harper's query functionality, where we actually search for an ordered list of nearest
410
+ * neighbors, using the provided sort/order definition object and performing the multi-layer skip-list search.
411
+ * This returns an iterable of the nearest neighbors to the provided target vector, with nearest ordered first.
412
+ * @param target
413
+ * @param value
414
+ * @param descending
415
+ * @param distance
416
+ * @param comparator
417
+ * @param context
418
+ */
419
+ search({
420
+ target,
421
+ value,
422
+ descending,
423
+ distance,
424
+ comparator,
425
+ }: {
426
+ target: number[];
427
+ value: number;
428
+ descending: boolean;
429
+ distance: string;
430
+ comparator: string;
431
+ }) {
432
+ let limit = 0; // zero is ignored, only used if set below
433
+ switch (comparator) {
434
+ case 'lt':
435
+ case 'le':
436
+ limit = value;
437
+ // fallthrough
438
+ case 'sort':
439
+ break;
440
+ default:
441
+ throw new ClientError(`Can not use "${comparator}" comparator with HNSW`);
442
+ }
443
+ if (descending) throw new ClientError(`Can not use descending sort order with HNSW`);
444
+ let distanceFunction: (a: number[], b: number[]) => number;
445
+ if (distance === 'cosine') distanceFunction = cosineDistance;
446
+ else if (distance === 'euclidean') distanceFunction = euclideanDistance;
447
+ else if (distance) throw new ClientError('Unknown distance function');
448
+ else distanceFunction = this.distance;
449
+ if (!target) throw new ClientError('A target vector must be provided for an HNSW query');
450
+ if (!Array.isArray(target)) throw new ClientError('The target vector must be an array');
451
+
452
+ let entryPoint = this.getEntryPoint();
453
+ if (!entryPoint) return [];
454
+ let entryPointId = entryPoint.id;
455
+ let results: Candidate[] = [];
456
+ // For each level from top to bottom
457
+ for (let l = entryPoint.level; l >= 0; l--) {
458
+ // Search for closest neighbors at current level
459
+ results = this.searchLayer(target, entryPointId, entryPoint, this.efConstructionSearch, l, distanceFunction);
460
+
461
+ if (results.length > 0) {
462
+ const neighbor = results[0]; // closest neighbor becomes new entry point
463
+ entryPoint = neighbor.node;
464
+ entryPointId = neighbor.id;
465
+ }
466
+ }
467
+ if (limit) results = results.filter((candidate) => candidate.distance < limit);
468
+ return results.map((candidate) => ({
469
+ // we return the result as an entry so we can provide distance as metadata
470
+ key: candidate.node.primaryKey, // return value
471
+ distance: candidate.distance,
472
+ }));
473
+ }
474
+ private checkSymmetry(id, node, options) {
475
+ if (!node) return;
476
+ let l = 0;
477
+ let connections: Candidate[];
478
+ while ((connections = node[l])) {
479
+ // verify that the level is not empty, otherwise this means we have an orphaned node
480
+ if (connections.length === 0) break;
481
+ for (const { id: neighbor } of connections) {
482
+ const neighborNode = this.indexStore.getSync(neighbor, options);
483
+ if (!neighborNode) {
484
+ logger.info?.('could not find neighbor node', neighborNode);
485
+ continue;
486
+ }
487
+ // verify that the connection is symmetrical
488
+ const symmetrical = neighborNode[l]?.find(({ id: nid }) => nid == id);
489
+ if (!symmetrical) {
490
+ logger.info?.('asymmetry detected', neighborNode[l]);
491
+ }
492
+ }
493
+ l++;
494
+ }
495
+ }
496
+ private addConnection(
497
+ fromId: number,
498
+ node: any,
499
+ toId: number,
500
+ level: number,
501
+ distance: number,
502
+ updateNode: (id: number, node?: Node) => any,
503
+ options: any
504
+ ) {
505
+ if (!node[level]) {
506
+ node[level] = [];
507
+ }
508
+
509
+ let maxConnections = level === 0 ? this.M << 1 : this.M;
510
+ if (this.optimizeRouting) maxConnections <<= 2; // bump up the max connections beyond traditional HNSW because we are naturally limiting
511
+ // have we exceeded the max connections (with 25% grace period)
512
+ if (node[level].length >= maxConnections + (maxConnections >> 2)) {
513
+ logger.debug?.('maxConnections reached, removing some connections', maxConnections);
514
+ // Get all connections with their similarities
515
+
516
+ // Sort by distance but prioritize nodes that have reverse connections
517
+ const connections = [...node[level]];
518
+ connections.sort((a, b) => {
519
+ return a.distance - b.distance;
520
+ });
521
+
522
+ // Keep the best connections
523
+ const keptConnections = connections.slice(0, maxConnections);
524
+ const removedConnections = connections.slice(maxConnections);
525
+
526
+ // Update this node's connections
527
+ node[level] = keptConnections;
528
+ // For removed connections, ensure there's still a path to them
529
+ for (const removed of removedConnections) {
530
+ let removedNode = updateNode(removed.id) ?? this.indexStore.getSync(removed.id, options);
531
+ if (removedNode) {
532
+ // Remove the reverse connection if it exists
533
+ if (removedNode[level]) {
534
+ removedNode = updateNode(removed.id, removedNode);
535
+ removedNode[level] = removedNode[level].filter(({ id }) => id !== fromId);
536
+ if (level === 0 && removedNode[level].length === 0) {
537
+ logger.info?.('should not remove last connection', fromId, toId);
538
+ }
539
+ }
540
+ }
541
+ }
542
+ }
543
+ if (node[level].find(({ id }) => id === toId)) {
544
+ logger.debug?.('already connected', fromId, toId);
545
+ } else {
546
+ node[level] = [...node[level], { id: toId, distance }]; // add
547
+ }
548
+
549
+ //this.indexStore.put(fromId, node, options);
550
+ //this.checkSymmetry(fromId, node, options);
551
+ }
552
+ validateConnectivity(startLevel: number = 0) {
553
+ const entryPoint = this.getEntryPoint();
554
+ const visited = new Set<number>();
555
+
556
+ // BFS from entry point to ensure all nodes are reachable
557
+ const queue = [entryPoint.id];
558
+ visited.add(entryPoint.id);
559
+ let connections = 0;
560
+
561
+ while (queue.length > 0) {
562
+ const currentId = queue.shift()!;
563
+ const current = this.indexStore.getSync(currentId);
564
+
565
+ for (let level = startLevel; level <= current.level; level++) {
566
+ for (const { id: neighborId } of current[level] || []) {
567
+ connections++;
568
+ if (!visited.has(neighborId)) {
569
+ visited.add(neighborId);
570
+ queue.push(neighborId);
571
+ }
572
+ }
573
+ }
574
+ }
575
+
576
+ // Check if all nodes are reachable
577
+ // This would require maintaining a separate set/count of all nodes
578
+ if (visited.size !== this.totalNodes) {
579
+ console.log('visited', visited.size, 'total', this.totalNodes);
580
+ }
581
+ return {
582
+ isFullyConnected: visited.size === this.totalNodes,
583
+ averageConnections: connections / visited.size,
584
+ };
585
+ }
586
+ get totalNodes() {
587
+ return Array.from(this.indexStore.getKeys({ start: 0, end: Infinity })).length;
588
+ }
589
+
590
+ /**
591
+ * This is used by the query planner to determine what order to apply conditions. It is our best guess at an estimated count.
592
+ * This unit is typically the number of records that need to be accessed to satisfy the query. We know that we will visit
593
+ * a minimum of efConstructionSearch nodes and a maximum of the total nodes (in absolute worst case).
594
+ * The original paper described the complexity as polylogarithmic. From my testing, the
595
+ * best and simplest guess at the number of nodes that need to be accessed is the geometric mean of the total number of nodes
596
+ * and the efConstruction parameter (for search), which clearly constrains the estimate to the correct range and is
597
+ * similar to polylogarithmic for realistic values.
598
+ *
599
+ * @returns
600
+ */
601
+ estimateCountAsSort() {
602
+ return Math.sqrt(this.indexStore.getStats().entryCount * this.efConstructionSearch);
603
+ }
604
+
605
+ /**
606
+ * This is used to resolve the vector property, which should be resolved to the distance when used in a sort comparator
607
+ * We also want to cache distance calculations so they can be accessed efficently later
608
+ * @param vector
609
+ * @param context
610
+ * @param entry
611
+ */
612
+ propertyResolver(vector: number[], context: any, entry: any) {
613
+ const sortDefinition = context?.sort;
614
+ if (sortDefinition) {
615
+ // set up a cache for these so they can be accessed by $distance and not be recalculated during a sort
616
+ let vectorDistances = sortDefinition.vectorDistances;
617
+ if (vectorDistances) {
618
+ const difference = vectorDistances.get(entry);
619
+ if (difference) return difference;
620
+ } else vectorDistances = context.vectorDistances = sortDefinition.vectorDistances = new Map();
621
+
622
+ let distanceFunction = this.distance;
623
+ if (sortDefinition.type)
624
+ distanceFunction = sortDefinition.distance === 'euclidean' ? euclideanDistance : cosineDistance;
625
+ const distance = distanceFunction(sortDefinition.target, vector);
626
+ vectorDistances.set(entry, distance);
627
+ return distance;
628
+ }
629
+ return vector;
630
+ }
631
+ }
632
+ type WithCopied = Connection[] & { copied: boolean };
633
+ type Candidate = {
634
+ id: number;
635
+ distance: number;
636
+ node: Node;
637
+ };
638
+ type SearchResults = Candidate[] & { visited: number };
@@ -0,0 +1,7 @@
1
+ import { HierarchicalNavigableSmallWorld } from './HierarchicalNavigableSmallWorld.ts';
2
+
3
+ export const CUSTOM_INDEXES = {
4
+ HNSW: HierarchicalNavigableSmallWorld,
5
+ // TODO: next up, is a Z-Order LSH algorithm:
6
+ // ZOrder: ZOrderLSH,
7
+ };
@@ -0,0 +1,38 @@
1
+ export function euclideanDistance(a: number[], b: number[]): number {
2
+ // Euclidean distance
3
+ if (!Array.isArray(a) || !Array.isArray(b)) {
4
+ throw new Error('Euclidean distance comparison requires an array');
5
+ }
6
+ let distanceSquared = 0;
7
+ const length = Math.max(a.length, b.length);
8
+ for (let i = 0; i < length; i++) {
9
+ const va = a[i] || 0;
10
+ const vb = b[i] || 0;
11
+ const distance = va - vb;
12
+ distanceSquared += distance * distance;
13
+ }
14
+ return distanceSquared; // technically distance is the square root, but skipping that doesn't change the order
15
+ }
16
+
17
+ export function cosineDistance(a: number[], b: number[]): number {
18
+ // Cosine similarity, negated so it can be a "distance" function
19
+ if (!Array.isArray(a) || !Array.isArray(b)) {
20
+ throw new Error('Cosine distance comparison requires an array');
21
+ }
22
+ let dotProduct = 0;
23
+ let magnitudeA = 0;
24
+ let magnitudeB = 0;
25
+ const length = Math.max(a.length, b.length);
26
+ for (let i = 0; i < length; i++) {
27
+ const va = a[i] || 0;
28
+ const vb = b[i] || 0;
29
+ dotProduct += va * vb;
30
+ magnitudeA += va * va;
31
+ magnitudeB += vb * vb;
32
+ }
33
+
34
+ magnitudeA = Math.sqrt(magnitudeA);
35
+ magnitudeB = Math.sqrt(magnitudeB);
36
+
37
+ return 1 - dotProduct / (magnitudeA * magnitudeB || 1);
38
+ }