@harperfast/harper 5.2.13 → 5.3.0-beta.1

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 (655) hide show
  1. package/agent/mcpTools.ts +1 -1
  2. package/agent/session.ts +25 -14
  3. package/bin/cliOperations.ts +58 -9
  4. package/bin/copyDb.ts +282 -59
  5. package/bin/deploySetup.ts +16 -5
  6. package/bin/harper.ts +1 -1
  7. package/bin/help.ts +4 -1
  8. package/bin/lite.ts +4 -1
  9. package/bin/restart.ts +120 -4
  10. package/bin/run.ts +6 -11
  11. package/bin/upgrade.js +7 -3
  12. package/bin/workloadIdentity.ts +119 -0
  13. package/components/Application.ts +3436 -242
  14. package/components/ApplicationScope.ts +8 -0
  15. package/components/EntryHandler.ts +59 -39
  16. package/components/OptionsWatcher.ts +440 -98
  17. package/components/RuntimeModuleTracker.ts +38 -7
  18. package/components/Scope.ts +56 -15
  19. package/components/awaitRestart.ts +84 -0
  20. package/components/componentLoader.ts +381 -32
  21. package/components/componentPreparationLock.ts +16 -5
  22. package/components/deploymentOperations.ts +4 -1
  23. package/components/deploymentRecorder.ts +9 -2
  24. package/components/mcp/adapters/harperHttp.ts +4 -0
  25. package/components/mcp/listChanged.ts +4 -0
  26. package/components/mcp/toolRegistry.ts +2 -0
  27. package/components/mcp/tools/operations.ts +9 -0
  28. package/components/mcp/tools/schemas/operationDescriptions.ts +2 -2
  29. package/components/operations.js +537 -113
  30. package/components/operationsValidation.js +98 -3
  31. package/components/packageComponent.ts +25 -1
  32. package/components/requestRestart.ts +11 -0
  33. package/components/status/ComponentStatusRegistry.ts +59 -0
  34. package/config/RootConfigWatcher.ts +240 -40
  35. package/config/configReadRetry.ts +62 -0
  36. package/config/configUtils.ts +357 -48
  37. package/config/harperConfigEnvVars.ts +170 -27
  38. package/config/parseConfigFile.ts +34 -0
  39. package/config/readConfigFileSync.ts +44 -0
  40. package/config/watcherArming.ts +59 -0
  41. package/config-root.schema.json +33 -0
  42. package/dataLayer/blobBackup.ts +160 -50
  43. package/dataLayer/delete.ts +6 -1
  44. package/dataLayer/harperBridge/ResourceBridge.ts +80 -10
  45. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
  46. package/dataLayer/hdbInfoController.ts +34 -1
  47. package/dataLayer/insert.ts +44 -1
  48. package/dataLayer/rocksdbBackup.ts +53 -10
  49. package/dataLayer/schema.ts +11 -1
  50. package/dataLayer/schemaDescribe.ts +8 -1
  51. package/dist/agent/mcpTools.js +1 -1
  52. package/dist/agent/mcpTools.js.map +1 -1
  53. package/dist/agent/session.d.ts +22 -0
  54. package/dist/agent/session.js +26 -15
  55. package/dist/agent/session.js.map +1 -1
  56. package/dist/bin/cliOperations.js +61 -9
  57. package/dist/bin/cliOperations.js.map +1 -1
  58. package/dist/bin/copyDb.d.ts +12 -1
  59. package/dist/bin/copyDb.js +248 -60
  60. package/dist/bin/copyDb.js.map +1 -1
  61. package/dist/bin/deploySetup.d.ts +2 -0
  62. package/dist/bin/deploySetup.js +11 -3
  63. package/dist/bin/deploySetup.js.map +1 -1
  64. package/dist/bin/harper.js +1 -1
  65. package/dist/bin/harper.js.map +1 -1
  66. package/dist/bin/help.js +4 -1
  67. package/dist/bin/help.js.map +1 -1
  68. package/dist/bin/lite.js +4 -1
  69. package/dist/bin/lite.js.map +1 -1
  70. package/dist/bin/restart.js +91 -6
  71. package/dist/bin/restart.js.map +1 -1
  72. package/dist/bin/run.js +4 -10
  73. package/dist/bin/run.js.map +1 -1
  74. package/dist/bin/upgrade.js +4 -3
  75. package/dist/bin/upgrade.js.map +1 -1
  76. package/dist/bin/workloadIdentity.d.ts +18 -0
  77. package/dist/bin/workloadIdentity.js +100 -0
  78. package/dist/bin/workloadIdentity.js.map +1 -0
  79. package/dist/components/Application.d.ts +235 -17
  80. package/dist/components/Application.js +3038 -238
  81. package/dist/components/Application.js.map +1 -1
  82. package/dist/components/ApplicationScope.d.ts +8 -0
  83. package/dist/components/ApplicationScope.js +7 -0
  84. package/dist/components/ApplicationScope.js.map +1 -1
  85. package/dist/components/EntryHandler.js +26 -10
  86. package/dist/components/EntryHandler.js.map +1 -1
  87. package/dist/components/OptionsWatcher.d.ts +4 -0
  88. package/dist/components/OptionsWatcher.js +440 -99
  89. package/dist/components/OptionsWatcher.js.map +1 -1
  90. package/dist/components/RuntimeModuleTracker.js +40 -6
  91. package/dist/components/RuntimeModuleTracker.js.map +1 -1
  92. package/dist/components/Scope.js +52 -13
  93. package/dist/components/Scope.js.map +1 -1
  94. package/dist/components/awaitRestart.d.ts +33 -0
  95. package/dist/components/awaitRestart.js +61 -0
  96. package/dist/components/awaitRestart.js.map +1 -0
  97. package/dist/components/componentLoader.d.ts +38 -1
  98. package/dist/components/componentLoader.js +313 -24
  99. package/dist/components/componentLoader.js.map +1 -1
  100. package/dist/components/componentPreparationLock.d.ts +5 -0
  101. package/dist/components/componentPreparationLock.js +14 -6
  102. package/dist/components/componentPreparationLock.js.map +1 -1
  103. package/dist/components/deploymentOperations.js +4 -1
  104. package/dist/components/deploymentOperations.js.map +1 -1
  105. package/dist/components/deploymentRecorder.d.ts +4 -2
  106. package/dist/components/deploymentRecorder.js +1 -0
  107. package/dist/components/deploymentRecorder.js.map +1 -1
  108. package/dist/components/mcp/adapters/harperHttp.js +4 -0
  109. package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
  110. package/dist/components/mcp/listChanged.js +5 -0
  111. package/dist/components/mcp/listChanged.js.map +1 -1
  112. package/dist/components/mcp/toolRegistry.d.ts +1 -0
  113. package/dist/components/mcp/toolRegistry.js.map +1 -1
  114. package/dist/components/mcp/tools/operations.d.ts +5 -0
  115. package/dist/components/mcp/tools/operations.js +9 -0
  116. package/dist/components/mcp/tools/operations.js.map +1 -1
  117. package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -2
  118. package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
  119. package/dist/components/operations.d.ts +28 -0
  120. package/dist/components/operations.js +476 -113
  121. package/dist/components/operations.js.map +1 -1
  122. package/dist/components/operationsValidation.js +97 -3
  123. package/dist/components/operationsValidation.js.map +1 -1
  124. package/dist/components/packageComponent.js +24 -0
  125. package/dist/components/packageComponent.js.map +1 -1
  126. package/dist/components/requestRestart.d.ts +1 -0
  127. package/dist/components/requestRestart.js +7 -0
  128. package/dist/components/requestRestart.js.map +1 -1
  129. package/dist/components/status/ComponentStatusRegistry.d.ts +0 -4
  130. package/dist/components/status/ComponentStatusRegistry.js +63 -0
  131. package/dist/components/status/ComponentStatusRegistry.js.map +1 -1
  132. package/dist/config/RootConfigWatcher.d.ts +9 -1
  133. package/dist/config/RootConfigWatcher.js +228 -37
  134. package/dist/config/RootConfigWatcher.js.map +1 -1
  135. package/dist/config/configReadRetry.d.ts +8 -0
  136. package/dist/config/configReadRetry.js +62 -0
  137. package/dist/config/configReadRetry.js.map +1 -0
  138. package/dist/config/configUtils.d.ts +11 -2
  139. package/dist/config/configUtils.js +304 -47
  140. package/dist/config/configUtils.js.map +1 -1
  141. package/dist/config/harperConfigEnvVars.d.ts +16 -0
  142. package/dist/config/harperConfigEnvVars.js +162 -25
  143. package/dist/config/harperConfigEnvVars.js.map +1 -1
  144. package/dist/config/parseConfigFile.d.ts +4 -0
  145. package/dist/config/parseConfigFile.js +35 -0
  146. package/dist/config/parseConfigFile.js.map +1 -0
  147. package/dist/config/readConfigFileSync.d.ts +1 -0
  148. package/dist/config/readConfigFileSync.js +47 -0
  149. package/dist/config/readConfigFileSync.js.map +1 -0
  150. package/dist/config/watcherArming.d.ts +15 -0
  151. package/dist/config/watcherArming.js +59 -0
  152. package/dist/config/watcherArming.js.map +1 -0
  153. package/dist/dataLayer/blobBackup.d.ts +49 -20
  154. package/dist/dataLayer/blobBackup.js +139 -50
  155. package/dist/dataLayer/blobBackup.js.map +1 -1
  156. package/dist/dataLayer/delete.js +1 -1
  157. package/dist/dataLayer/delete.js.map +1 -1
  158. package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +14 -1
  159. package/dist/dataLayer/harperBridge/ResourceBridge.js +72 -12
  160. package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
  161. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.d.ts +3 -1
  162. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
  163. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js.map +1 -1
  164. package/dist/dataLayer/hdbInfoController.d.ts +10 -0
  165. package/dist/dataLayer/hdbInfoController.js +30 -1
  166. package/dist/dataLayer/hdbInfoController.js.map +1 -1
  167. package/dist/dataLayer/insert.d.ts +9 -1
  168. package/dist/dataLayer/insert.js +30 -0
  169. package/dist/dataLayer/insert.js.map +1 -1
  170. package/dist/dataLayer/rocksdbBackup.d.ts +2 -2
  171. package/dist/dataLayer/rocksdbBackup.js +45 -8
  172. package/dist/dataLayer/rocksdbBackup.js.map +1 -1
  173. package/dist/dataLayer/schema.js +8 -0
  174. package/dist/dataLayer/schema.js.map +1 -1
  175. package/dist/dataLayer/schemaDescribe.js +8 -1
  176. package/dist/dataLayer/schemaDescribe.js.map +1 -1
  177. package/dist/index.d.ts +2 -1
  178. package/dist/index.js +4 -1
  179. package/dist/index.js.map +1 -1
  180. package/dist/json/systemSchema.json +55 -0
  181. package/dist/resources/DatabaseTransaction.d.ts +77 -0
  182. package/dist/resources/DatabaseTransaction.js +586 -54
  183. package/dist/resources/DatabaseTransaction.js.map +1 -1
  184. package/dist/resources/LMDBTransaction.d.ts +2 -1
  185. package/dist/resources/LMDBTransaction.js +43 -6
  186. package/dist/resources/LMDBTransaction.js.map +1 -1
  187. package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
  188. package/dist/resources/PrimaryRocksDatabase.js +49 -5
  189. package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
  190. package/dist/resources/RecordEncoder.d.ts +20 -0
  191. package/dist/resources/RecordEncoder.js +110 -9
  192. package/dist/resources/RecordEncoder.js.map +1 -1
  193. package/dist/resources/RequestTarget.d.ts +2 -0
  194. package/dist/resources/RequestTarget.js.map +1 -1
  195. package/dist/resources/Resource.js +117 -24
  196. package/dist/resources/Resource.js.map +1 -1
  197. package/dist/resources/ResourceInterface.d.ts +28 -1
  198. package/dist/resources/ResourceInterface.js.map +1 -1
  199. package/dist/resources/RocksIndexStore.d.ts +6 -1
  200. package/dist/resources/RocksIndexStore.js +24 -9
  201. package/dist/resources/RocksIndexStore.js.map +1 -1
  202. package/dist/resources/RocksTransactionLogStore.d.ts +24 -1
  203. package/dist/resources/RocksTransactionLogStore.js +160 -49
  204. package/dist/resources/RocksTransactionLogStore.js.map +1 -1
  205. package/dist/resources/Table.d.ts +165 -10
  206. package/dist/resources/Table.js +1805 -303
  207. package/dist/resources/Table.js.map +1 -1
  208. package/dist/resources/analytics/write.js +10 -3
  209. package/dist/resources/analytics/write.js.map +1 -1
  210. package/dist/resources/auditStore.d.ts +181 -2
  211. package/dist/resources/auditStore.js +640 -29
  212. package/dist/resources/auditStore.js.map +1 -1
  213. package/dist/resources/blob.d.ts +129 -9
  214. package/dist/resources/blob.js +992 -114
  215. package/dist/resources/blob.js.map +1 -1
  216. package/dist/resources/branchDatabase.d.ts +48 -0
  217. package/dist/resources/branchDatabase.js +892 -0
  218. package/dist/resources/branchDatabase.js.map +1 -0
  219. package/dist/resources/crdt.js +50 -12
  220. package/dist/resources/crdt.js.map +1 -1
  221. package/dist/resources/dataLoader.js +3 -4
  222. package/dist/resources/dataLoader.js.map +1 -1
  223. package/dist/resources/databases.d.ts +157 -14
  224. package/dist/resources/databases.js +1462 -325
  225. package/dist/resources/databases.js.map +1 -1
  226. package/dist/resources/defineTable.d.ts +10 -2
  227. package/dist/resources/defineTable.js +9 -1
  228. package/dist/resources/defineTable.js.map +1 -1
  229. package/dist/resources/derivedIndexRegistry.d.ts +5 -0
  230. package/dist/resources/derivedIndexRegistry.js +68 -0
  231. package/dist/resources/derivedIndexRegistry.js.map +1 -0
  232. package/dist/resources/derivedIndexRuntime.d.ts +215 -0
  233. package/dist/resources/derivedIndexRuntime.js +2027 -0
  234. package/dist/resources/derivedIndexRuntime.js.map +1 -0
  235. package/dist/resources/graphql.d.ts +1 -1
  236. package/dist/resources/graphql.js +52 -16
  237. package/dist/resources/graphql.js.map +1 -1
  238. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +103 -9
  239. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +854 -41
  240. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
  241. package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
  242. package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
  243. package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
  244. package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
  245. package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
  246. package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
  247. package/dist/resources/longLivedTransactions.d.ts +71 -0
  248. package/dist/resources/longLivedTransactions.js +358 -0
  249. package/dist/resources/longLivedTransactions.js.map +1 -0
  250. package/dist/resources/models/backendRegistry.d.ts +26 -0
  251. package/dist/resources/models/backendRegistry.js +60 -2
  252. package/dist/resources/models/backendRegistry.js.map +1 -1
  253. package/dist/resources/models/bootstrap.d.ts +33 -1
  254. package/dist/resources/models/bootstrap.js +416 -31
  255. package/dist/resources/models/bootstrap.js.map +1 -1
  256. package/dist/resources/nodeIdMapping.d.ts +5 -0
  257. package/dist/resources/nodeIdMapping.js +49 -0
  258. package/dist/resources/nodeIdMapping.js.map +1 -1
  259. package/dist/resources/recordLock.d.ts +123 -0
  260. package/dist/resources/recordLock.js +315 -0
  261. package/dist/resources/recordLock.js.map +1 -0
  262. package/dist/resources/recordLockCoordinator.d.ts +557 -0
  263. package/dist/resources/recordLockCoordinator.js +2565 -0
  264. package/dist/resources/recordLockCoordinator.js.map +1 -0
  265. package/dist/resources/replayLogs.d.ts +14 -1
  266. package/dist/resources/replayLogs.js +157 -24
  267. package/dist/resources/replayLogs.js.map +1 -1
  268. package/dist/resources/replayLogsGuards.d.ts +94 -7
  269. package/dist/resources/replayLogsGuards.js +111 -7
  270. package/dist/resources/replayLogsGuards.js.map +1 -1
  271. package/dist/resources/replicatedApplyFailure.d.ts +16 -0
  272. package/dist/resources/replicatedApplyFailure.js +63 -0
  273. package/dist/resources/replicatedApplyFailure.js.map +1 -0
  274. package/dist/resources/scheduler/scheduler.js +3 -3
  275. package/dist/resources/scheduler/scheduler.js.map +1 -1
  276. package/dist/resources/search.d.ts +10 -4
  277. package/dist/resources/search.js +283 -37
  278. package/dist/resources/search.js.map +1 -1
  279. package/dist/resources/tracked.d.ts +5 -1
  280. package/dist/resources/tracked.js +74 -23
  281. package/dist/resources/tracked.js.map +1 -1
  282. package/dist/resources/transactionBroadcast.d.ts +1 -1
  283. package/dist/resources/transactionBroadcast.js +2 -2
  284. package/dist/resources/transactionBroadcast.js.map +1 -1
  285. package/dist/security/auth.js +61 -30
  286. package/dist/security/auth.js.map +1 -1
  287. package/dist/security/authn/oidc/claims.d.ts +22 -0
  288. package/dist/security/authn/oidc/claims.js +71 -0
  289. package/dist/security/authn/oidc/claims.js.map +1 -0
  290. package/dist/security/authn/oidc/identityToken.d.ts +27 -0
  291. package/dist/security/authn/oidc/identityToken.js +111 -0
  292. package/dist/security/authn/oidc/identityToken.js.map +1 -0
  293. package/dist/security/authn/oidc/jwks.d.ts +25 -0
  294. package/dist/security/authn/oidc/jwks.js +261 -0
  295. package/dist/security/authn/oidc/jwks.js.map +1 -0
  296. package/dist/security/authn/oidc/providers/generic.d.ts +13 -0
  297. package/dist/security/authn/oidc/providers/generic.js +34 -0
  298. package/dist/security/authn/oidc/providers/generic.js.map +1 -0
  299. package/dist/security/authn/oidc/providers/githubActions.d.ts +11 -0
  300. package/dist/security/authn/oidc/providers/githubActions.js +129 -0
  301. package/dist/security/authn/oidc/providers/githubActions.js.map +1 -0
  302. package/dist/security/authn/oidc/providers/index.d.ts +37 -0
  303. package/dist/security/authn/oidc/providers/index.js +24 -0
  304. package/dist/security/authn/oidc/providers/index.js.map +1 -0
  305. package/dist/security/authn/oidc/tokenExchange.d.ts +12 -0
  306. package/dist/security/authn/oidc/tokenExchange.js +306 -0
  307. package/dist/security/authn/oidc/tokenExchange.js.map +1 -0
  308. package/dist/security/authn/oidc/trustPolicyOperations.d.ts +49 -0
  309. package/dist/security/authn/oidc/trustPolicyOperations.js +358 -0
  310. package/dist/security/authn/oidc/trustPolicyOperations.js.map +1 -0
  311. package/dist/security/authn/oidc/types.d.ts +38 -0
  312. package/dist/security/authn/oidc/types.js +6 -0
  313. package/dist/security/authn/oidc/types.js.map +1 -0
  314. package/dist/security/certificateVerification/index.js +40 -11
  315. package/dist/security/certificateVerification/index.js.map +1 -1
  316. package/dist/security/certificateVerification/trustedIssuers.d.ts +24 -0
  317. package/dist/security/certificateVerification/trustedIssuers.js +79 -0
  318. package/dist/security/certificateVerification/trustedIssuers.js.map +1 -0
  319. package/dist/security/certificateVerification/types.d.ts +1 -0
  320. package/dist/security/credentialProvenance.d.ts +35 -0
  321. package/dist/security/credentialProvenance.js +51 -0
  322. package/dist/security/credentialProvenance.js.map +1 -0
  323. package/dist/security/credentialRejection.d.ts +4 -0
  324. package/dist/security/credentialRejection.js +24 -0
  325. package/dist/security/credentialRejection.js.map +1 -0
  326. package/dist/security/deferredAuthentication.d.ts +36 -0
  327. package/dist/security/deferredAuthentication.js +70 -0
  328. package/dist/security/deferredAuthentication.js.map +1 -0
  329. package/dist/security/impersonation.d.ts +21 -0
  330. package/dist/security/impersonation.js +108 -9
  331. package/dist/security/impersonation.js.map +1 -1
  332. package/dist/security/jsLoader.d.ts +6 -0
  333. package/dist/security/jsLoader.js +77 -15
  334. package/dist/security/jsLoader.js.map +1 -1
  335. package/dist/security/keys.js +301 -71
  336. package/dist/security/keys.js.map +1 -1
  337. package/dist/security/operationScope.d.ts +21 -0
  338. package/dist/security/operationScope.js +36 -0
  339. package/dist/security/operationScope.js.map +1 -0
  340. package/dist/security/permissionsTranslator.js +21 -0
  341. package/dist/security/permissionsTranslator.js.map +1 -1
  342. package/dist/security/tokenAuthentication.d.ts +19 -1
  343. package/dist/security/tokenAuthentication.js +191 -10
  344. package/dist/security/tokenAuthentication.js.map +1 -1
  345. package/dist/security/user.js +4 -3
  346. package/dist/security/user.js.map +1 -1
  347. package/dist/server/DurableSubscriptionsSession.d.ts +2 -2
  348. package/dist/server/DurableSubscriptionsSession.js +67 -10
  349. package/dist/server/DurableSubscriptionsSession.js.map +1 -1
  350. package/dist/server/REST.js +106 -2
  351. package/dist/server/REST.js.map +1 -1
  352. package/dist/server/graphqlQuerying.js +4 -0
  353. package/dist/server/graphqlQuerying.js.map +1 -1
  354. package/dist/server/http.d.ts +16 -1
  355. package/dist/server/http.js +122 -17
  356. package/dist/server/http.js.map +1 -1
  357. package/dist/server/itc/serverHandlers.js +8 -1
  358. package/dist/server/itc/serverHandlers.js.map +1 -1
  359. package/dist/server/jobs/jobProcess.js +6 -2
  360. package/dist/server/jobs/jobProcess.js.map +1 -1
  361. package/dist/server/jobs/jobs.js +4 -1
  362. package/dist/server/jobs/jobs.js.map +1 -1
  363. package/dist/server/liveSubscriptionAuth.d.ts +26 -4
  364. package/dist/server/liveSubscriptionAuth.js +105 -39
  365. package/dist/server/liveSubscriptionAuth.js.map +1 -1
  366. package/dist/server/loadRootComponents.js +49 -10
  367. package/dist/server/loadRootComponents.js.map +1 -1
  368. package/dist/server/mqtt.d.ts +2 -0
  369. package/dist/server/mqtt.js +165 -30
  370. package/dist/server/mqtt.js.map +1 -1
  371. package/dist/server/nodeName.d.ts +2 -0
  372. package/dist/server/nodeName.js +107 -23
  373. package/dist/server/nodeName.js.map +1 -1
  374. package/dist/server/serverHelpers/Headers.d.ts +27 -0
  375. package/dist/server/serverHelpers/Headers.js +145 -1
  376. package/dist/server/serverHelpers/Headers.js.map +1 -1
  377. package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
  378. package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
  379. package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
  380. package/dist/server/serverHelpers/Request.d.ts +5 -10
  381. package/dist/server/serverHelpers/Request.js +38 -136
  382. package/dist/server/serverHelpers/Request.js.map +1 -1
  383. package/dist/server/serverHelpers/contentTypes.d.ts +11 -0
  384. package/dist/server/serverHelpers/contentTypes.js +221 -40
  385. package/dist/server/serverHelpers/contentTypes.js.map +1 -1
  386. package/dist/server/serverHelpers/deployValidationState.d.ts +3 -0
  387. package/dist/server/serverHelpers/deployValidationState.js +9 -19
  388. package/dist/server/serverHelpers/deployValidationState.js.map +1 -1
  389. package/dist/server/serverHelpers/operationAuthorizationState.d.ts +12 -0
  390. package/dist/server/serverHelpers/operationAuthorizationState.js +24 -2
  391. package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -1
  392. package/dist/server/serverHelpers/registeredOperations.d.ts +5 -4
  393. package/dist/server/serverHelpers/registeredOperations.js +74 -21
  394. package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
  395. package/dist/server/serverHelpers/requestSanitization.d.ts +11 -0
  396. package/dist/server/serverHelpers/requestSanitization.js +20 -0
  397. package/dist/server/serverHelpers/requestSanitization.js.map +1 -0
  398. package/dist/server/serverHelpers/serverHandlers.js +6 -3
  399. package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
  400. package/dist/server/serverHelpers/serverUtilities.d.ts +18 -0
  401. package/dist/server/serverHelpers/serverUtilities.js +178 -29
  402. package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
  403. package/dist/server/serverHelpers/sharedMessageEncoding.d.ts +67 -0
  404. package/dist/server/serverHelpers/sharedMessageEncoding.js +280 -0
  405. package/dist/server/serverHelpers/sharedMessageEncoding.js.map +1 -0
  406. package/dist/server/serverHelpers/uwsServer.js +19 -1
  407. package/dist/server/serverHelpers/uwsServer.js.map +1 -1
  408. package/dist/server/static.js +24 -28
  409. package/dist/server/static.js.map +1 -1
  410. package/dist/server/storageReclamation.d.ts +5 -0
  411. package/dist/server/storageReclamation.js +17 -1
  412. package/dist/server/storageReclamation.js.map +1 -1
  413. package/dist/server/threads/isolatedApplications.d.ts +47 -0
  414. package/dist/server/threads/isolatedApplications.js +171 -0
  415. package/dist/server/threads/isolatedApplications.js.map +1 -0
  416. package/dist/server/threads/itc.d.ts +7 -2
  417. package/dist/server/threads/itc.js +5 -1
  418. package/dist/server/threads/itc.js.map +1 -1
  419. package/dist/server/threads/logRotationTransport.d.ts +1 -0
  420. package/dist/server/threads/logRotationTransport.js +33 -0
  421. package/dist/server/threads/logRotationTransport.js.map +1 -0
  422. package/dist/server/threads/manageThreads.d.ts +83 -3
  423. package/dist/server/threads/manageThreads.js +769 -75
  424. package/dist/server/threads/manageThreads.js.map +1 -1
  425. package/dist/server/threads/socketRouter.d.ts +1 -0
  426. package/dist/server/threads/socketRouter.js +277 -31
  427. package/dist/server/threads/socketRouter.js.map +1 -1
  428. package/dist/server/threads/threadHeapMemory.d.ts +2 -0
  429. package/dist/server/threads/threadHeapMemory.js +31 -0
  430. package/dist/server/threads/threadHeapMemory.js.map +1 -0
  431. package/dist/server/threads/threadServer.js +76 -22
  432. package/dist/server/threads/threadServer.js.map +1 -1
  433. package/dist/sqlEngine/config.d.ts +1 -3
  434. package/dist/sqlEngine/config.js +19 -16
  435. package/dist/sqlEngine/config.js.map +1 -1
  436. package/dist/sqlTranslator/index.d.ts +1 -1
  437. package/dist/sqlTranslator/index.js +30 -7
  438. package/dist/sqlTranslator/index.js.map +1 -1
  439. package/dist/upgrade/directives/5-3-0.d.ts +7 -0
  440. package/dist/upgrade/directives/5-3-0.js +148 -0
  441. package/dist/upgrade/directives/5-3-0.js.map +1 -0
  442. package/dist/upgrade/directives/directivesController.js +2 -1
  443. package/dist/upgrade/directives/directivesController.js.map +1 -1
  444. package/dist/utility/OperationFunctionCaller.js +2 -1
  445. package/dist/utility/OperationFunctionCaller.js.map +1 -1
  446. package/dist/utility/common_utils.d.ts +16 -0
  447. package/dist/utility/common_utils.js +32 -6
  448. package/dist/utility/common_utils.js.map +1 -1
  449. package/dist/utility/componentNames.d.ts +8 -0
  450. package/dist/utility/componentNames.js +12 -1
  451. package/dist/utility/componentNames.js.map +1 -1
  452. package/dist/utility/environment/environmentManager.js +3 -6
  453. package/dist/utility/environment/environmentManager.js.map +1 -1
  454. package/dist/utility/environment/systemInformation.d.ts +1 -0
  455. package/dist/utility/environment/systemInformation.js +1 -0
  456. package/dist/utility/environment/systemInformation.js.map +1 -1
  457. package/dist/utility/errors/commonErrors.d.ts +2 -0
  458. package/dist/utility/errors/commonErrors.js +2 -0
  459. package/dist/utility/errors/commonErrors.js.map +1 -1
  460. package/dist/utility/errors/hdbError.d.ts +33 -0
  461. package/dist/utility/errors/hdbError.js +58 -1
  462. package/dist/utility/errors/hdbError.js.map +1 -1
  463. package/dist/utility/globalSchema.d.ts +18 -0
  464. package/dist/utility/hdbTerms.d.ts +18 -0
  465. package/dist/utility/hdbTerms.js +20 -2
  466. package/dist/utility/hdbTerms.js.map +1 -1
  467. package/dist/utility/logging/harper_logger.d.ts +2 -0
  468. package/dist/utility/logging/harper_logger.js +286 -30
  469. package/dist/utility/logging/harper_logger.js.map +1 -1
  470. package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
  471. package/dist/utility/logging/logGenerationCoordinator.js +184 -0
  472. package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
  473. package/dist/utility/logging/logRotation.d.ts +46 -0
  474. package/dist/utility/logging/logRotation.js +365 -0
  475. package/dist/utility/logging/logRotation.js.map +1 -0
  476. package/dist/utility/logging/logRotator.d.ts +1 -1
  477. package/dist/utility/logging/logRotator.js +192 -85
  478. package/dist/utility/logging/logRotator.js.map +1 -1
  479. package/dist/utility/nodeIdentity.d.ts +9 -0
  480. package/dist/utility/nodeIdentity.js +58 -0
  481. package/dist/utility/nodeIdentity.js.map +1 -0
  482. package/dist/utility/npmUtilities.js +11 -7
  483. package/dist/utility/npmUtilities.js.map +1 -1
  484. package/dist/utility/operationPermissions.d.ts +3 -1
  485. package/dist/utility/operationPermissions.js +16 -1
  486. package/dist/utility/operationPermissions.js.map +1 -1
  487. package/dist/utility/operation_authorization.d.ts +10 -7
  488. package/dist/utility/operation_authorization.js +212 -41
  489. package/dist/utility/operation_authorization.js.map +1 -1
  490. package/dist/utility/watchPath.d.ts +29 -0
  491. package/dist/utility/watchPath.js +68 -0
  492. package/dist/utility/watchPath.js.map +1 -0
  493. package/dist/utility/watcherFallback.d.ts +41 -0
  494. package/dist/utility/watcherFallback.js +153 -0
  495. package/dist/utility/watcherFallback.js.map +1 -1
  496. package/dist/validation/configValidator.d.ts +12 -0
  497. package/dist/validation/configValidator.js +205 -75
  498. package/dist/validation/configValidator.js.map +1 -1
  499. package/dist/validation/installValidator.js +12 -0
  500. package/dist/validation/installValidator.js.map +1 -1
  501. package/dist/validation/validationWrapper.d.ts +11 -0
  502. package/dist/validation/validationWrapper.js +16 -3
  503. package/dist/validation/validationWrapper.js.map +1 -1
  504. package/index.ts +8 -0
  505. package/json/systemSchema.json +55 -0
  506. package/npm-shrinkwrap.json +286 -194
  507. package/package.json +15 -7
  508. package/resources/DESIGN.md +219 -52
  509. package/resources/DatabaseTransaction.ts +657 -52
  510. package/resources/LMDBTransaction.ts +46 -6
  511. package/resources/PrimaryRocksDatabase.ts +46 -7
  512. package/resources/RecordEncoder.ts +124 -9
  513. package/resources/RequestTarget.ts +2 -0
  514. package/resources/Resource.ts +114 -22
  515. package/resources/ResourceInterface.ts +31 -0
  516. package/resources/RocksIndexStore.ts +30 -9
  517. package/resources/RocksTransactionLogStore.ts +188 -51
  518. package/resources/Table.ts +1960 -301
  519. package/resources/analytics/write.ts +10 -3
  520. package/resources/auditStore.ts +647 -32
  521. package/resources/blob.ts +1029 -110
  522. package/resources/branchDatabase.ts +941 -0
  523. package/resources/crdt.ts +76 -12
  524. package/resources/dataLoader.ts +3 -4
  525. package/resources/databases.ts +1584 -320
  526. package/resources/defineTable.ts +18 -2
  527. package/resources/derivedIndexRegistry.ts +56 -0
  528. package/resources/derivedIndexRuntime.ts +2292 -0
  529. package/resources/graphql.ts +72 -17
  530. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +911 -48
  531. package/resources/indexes/hnswDerivedIndex.ts +531 -0
  532. package/resources/indexes/hnswPlaneBinding.ts +174 -0
  533. package/resources/longLivedTransactions.ts +360 -0
  534. package/resources/models/backendRegistry.ts +84 -2
  535. package/resources/models/bootstrap.ts +473 -28
  536. package/resources/nodeIdMapping.ts +50 -0
  537. package/resources/recordLock.ts +419 -0
  538. package/resources/recordLockCoordinator.ts +3043 -0
  539. package/resources/replayLogs.ts +152 -26
  540. package/resources/replayLogsGuards.ts +171 -8
  541. package/resources/replicatedApplyFailure.ts +77 -0
  542. package/resources/scheduler/scheduler.ts +4 -4
  543. package/resources/search.ts +288 -46
  544. package/resources/tracked.ts +73 -22
  545. package/resources/transactionBroadcast.ts +3 -3
  546. package/security/auth.ts +68 -29
  547. package/security/authn/oidc/claims.ts +72 -0
  548. package/security/authn/oidc/identityToken.ts +129 -0
  549. package/security/authn/oidc/jwks.ts +260 -0
  550. package/security/authn/oidc/providers/generic.ts +40 -0
  551. package/security/authn/oidc/providers/githubActions.ts +137 -0
  552. package/security/authn/oidc/providers/index.ts +52 -0
  553. package/security/authn/oidc/tokenExchange.ts +300 -0
  554. package/security/authn/oidc/trustPolicyOperations.ts +343 -0
  555. package/security/authn/oidc/types.ts +41 -0
  556. package/security/certificateVerification/index.ts +54 -13
  557. package/security/certificateVerification/trustedIssuers.ts +76 -0
  558. package/security/certificateVerification/types.ts +1 -0
  559. package/security/credentialProvenance.ts +47 -0
  560. package/security/credentialRejection.ts +22 -0
  561. package/security/deferredAuthentication.ts +71 -0
  562. package/security/impersonation.ts +117 -12
  563. package/security/jsLoader.ts +83 -18
  564. package/security/keys.ts +298 -72
  565. package/security/operationScope.ts +33 -0
  566. package/security/permissionsTranslator.js +23 -0
  567. package/security/tokenAuthentication.ts +233 -12
  568. package/security/user.ts +4 -3
  569. package/server/DESIGN.md +194 -16
  570. package/server/DurableSubscriptionsSession.ts +71 -11
  571. package/server/REST.ts +115 -4
  572. package/server/graphqlQuerying.ts +4 -0
  573. package/server/http.ts +133 -20
  574. package/server/itc/serverHandlers.js +8 -1
  575. package/server/jobs/jobProcess.ts +8 -2
  576. package/server/jobs/jobs.ts +4 -1
  577. package/server/liveSubscriptionAuth.ts +129 -46
  578. package/server/loadRootComponents.js +50 -8
  579. package/server/mqtt.ts +179 -38
  580. package/server/nodeName.ts +103 -21
  581. package/server/serverHelpers/Headers.ts +135 -0
  582. package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
  583. package/server/serverHelpers/Request.ts +33 -131
  584. package/server/serverHelpers/contentTypes.ts +217 -36
  585. package/server/serverHelpers/deployValidationState.ts +24 -13
  586. package/server/serverHelpers/operationAuthorizationState.ts +34 -3
  587. package/server/serverHelpers/registeredOperations.ts +79 -22
  588. package/server/serverHelpers/requestSanitization.ts +15 -0
  589. package/server/serverHelpers/serverHandlers.js +6 -3
  590. package/server/serverHelpers/serverUtilities.ts +232 -40
  591. package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
  592. package/server/serverHelpers/uwsServer.ts +17 -2
  593. package/server/static.ts +23 -29
  594. package/server/storageReclamation.ts +15 -2
  595. package/server/threads/isolatedApplications.ts +157 -0
  596. package/server/threads/itc.js +11 -1
  597. package/server/threads/logRotationTransport.ts +40 -0
  598. package/server/threads/manageThreads.js +771 -66
  599. package/server/threads/socketRouter.ts +291 -30
  600. package/server/threads/threadHeapMemory.ts +26 -0
  601. package/server/threads/threadServer.js +73 -22
  602. package/sqlTranslator/index.ts +31 -8
  603. package/studio/web/assets/{Chat-4RrB5134.js → Chat-D3j-1yY1.js} +1 -1
  604. package/studio/web/assets/{FloatingChat-omlNMDcJ.js → FloatingChat-BxJGYcfB.js} +3 -3
  605. package/studio/web/assets/{apiToken-Bke3wvfZ.js → apiToken-CT55oWOe.js} +1 -1
  606. package/studio/web/assets/{applications-DvFDYJgK.js → applications-D9Ct9_vm.js} +1 -1
  607. package/studio/web/assets/{cssMode-C1vRa7zh.js → cssMode-DV8H7VwA.js} +1 -1
  608. package/studio/web/assets/{editor-3XRWEDWX.js → editor-uatc0unt.js} +1 -1
  609. package/studio/web/assets/{html-CTY5tdMr.js → html-Bm6D6paN.js} +1 -1
  610. package/studio/web/assets/{htmlMode-CG1vSD9t.js → htmlMode-CEn7tpLG.js} +1 -1
  611. package/studio/web/assets/{index-Dfpeofdu.js → index-BIXW6Pu4.js} +5 -5
  612. package/studio/web/assets/{index.lazy-B1VOIv-t.js → index.lazy-UI7L-Vrk.js} +1 -1
  613. package/studio/web/assets/{javascript-CJeJzGnI.js → javascript-CJ0G3AFZ.js} +1 -1
  614. package/studio/web/assets/{jsonMode-CYPBwM82.js → jsonMode-DQADAYEa.js} +1 -1
  615. package/studio/web/assets/{languageServices-IKH4GUHl.js → languageServices-CAQJXWcI.js} +1 -1
  616. package/studio/web/assets/{lspLanguageFeatures-BC8_gxKG.js → lspLanguageFeatures-CCQ8P5sY.js} +1 -1
  617. package/studio/web/assets/{notifications-BfKBpYcq.js → notifications-BbxTU6Aw.js} +1 -1
  618. package/studio/web/assets/{notifications-DFbArTfC.js → notifications-Cvb3P1lB.js} +1 -1
  619. package/studio/web/assets/{profile-Q4-T6c-S.js → profile-Yyb7gsvL.js} +1 -1
  620. package/studio/web/assets/{regions-CtkV0xje.js → regions-OgjGHlU5.js} +1 -1
  621. package/studio/web/assets/{register-1ZZuMsiA.js → register-6qwNEOY3.js} +2 -2
  622. package/studio/web/assets/{setComponentFile-ZWLcWv5X.js → setComponentFile-BilDMtgB.js} +1 -1
  623. package/studio/web/assets/{setup-DWprJyJy.js → setup-J6qJ7OIU.js} +2 -2
  624. package/studio/web/assets/{status--aNm8isn.js → status-0RWGcfyD.js} +1 -1
  625. package/studio/web/assets/{toggleHighContrast-Cq_lt3XD.js → toggleHighContrast-BIn-vErT.js} +1 -1
  626. package/studio/web/assets/{tsMode-pjgytARx.js → tsMode-DgUXku4d.js} +1 -1
  627. package/studio/web/assets/{typescript-Cdg0mqUh.js → typescript-C9orXcsM.js} +1 -1
  628. package/studio/web/assets/{useEntityRestURL-RZhaY8Rn.js → useEntityRestURL-BEoXXbUB.js} +1 -1
  629. package/studio/web/assets/{workers-BgoXIqQe.js → workers-JVzSDmgx.js} +1 -1
  630. package/studio/web/assets/{xml-BwSeDMiP.js → xml-Cq-S8S4X.js} +1 -1
  631. package/studio/web/assets/{yaml-DotCUG5l.js → yaml-sfoRdh1M.js} +1 -1
  632. package/studio/web/index.html +1 -1
  633. package/upgrade/directives/5-3-0.ts +132 -0
  634. package/upgrade/directives/directivesController.ts +2 -1
  635. package/utility/OperationFunctionCaller.ts +2 -1
  636. package/utility/common_utils.ts +30 -5
  637. package/utility/componentNames.ts +12 -0
  638. package/utility/environment/environmentManager.ts +3 -7
  639. package/utility/environment/systemInformation.ts +7 -0
  640. package/utility/errors/commonErrors.ts +4 -0
  641. package/utility/errors/hdbError.ts +57 -0
  642. package/utility/hdbTerms.ts +19 -0
  643. package/utility/logging/harper_logger.ts +278 -26
  644. package/utility/logging/logGenerationCoordinator.ts +196 -0
  645. package/utility/logging/logRotation.ts +367 -0
  646. package/utility/logging/logRotator.ts +213 -81
  647. package/utility/nodeIdentity.ts +45 -0
  648. package/utility/npmUtilities.ts +12 -8
  649. package/utility/operationPermissions.ts +18 -1
  650. package/utility/operation_authorization.ts +231 -42
  651. package/utility/watchPath.ts +63 -0
  652. package/utility/watcherFallback.ts +148 -0
  653. package/validation/configValidator.ts +215 -75
  654. package/validation/installValidator.ts +15 -0
  655. package/validation/validationWrapper.ts +18 -4
@@ -0,0 +1,531 @@
1
+ import { ClientError } from '../../utility/errors/hdbError.ts';
2
+ import { loggerWithTag } from '../../utility/logging/logger.ts';
3
+ import type { Id } from '../ResourceInterface.ts';
4
+ import type { RocksTransactionLogStore } from '../RocksTransactionLogStore.ts';
5
+ import {
6
+ DERIVED_INDEX_ACCEPTED,
7
+ DERIVED_INDEX_DEFERRED,
8
+ DerivedIndexRuntime,
9
+ readDerivedIndexReadiness,
10
+ readDerivedIndexCoverage,
11
+ sameDerivedIndexPositions,
12
+ type DerivedIndexBackend,
13
+ type DerivedIndexBackendHost,
14
+ type DerivedIndexBackendStateChange,
15
+ type DerivedIndexBatch,
16
+ type DerivedIndexCursor,
17
+ type DerivedIndexCoverage,
18
+ type DerivedIndexPositions,
19
+ type DerivedIndexDeliveryResult,
20
+ type DerivedIndexFlushReason,
21
+ type DerivedIndexMutation,
22
+ type DerivedIndexReadiness,
23
+ } from '../derivedIndexRuntime.ts';
24
+
25
+ const logger = loggerWithTag('HNSW');
26
+
27
+ /** The one durable cursor vector of a file-primary HNSW index, stored beside its node mappings. */
28
+ export const DERIVED_INDEX_CURSOR_KEY = Symbol.for('derived-index-cursor');
29
+ export const DEFAULT_MAX_INDEX_LAG_MILLISECONDS = 3000;
30
+ export const MAX_WAIT_FOR_INDEX_MILLISECONDS = 30_000;
31
+
32
+ export type DerivedNativeIndexHost = {
33
+ readiness: () => DerivedIndexReadiness;
34
+ coverage: (maxLagMilliseconds: number) => DerivedIndexCoverage;
35
+ waitForCoverage: (since: bigint, timeout: number, signal?: AbortSignal) => Promise<void>;
36
+ requestRebuild: () => boolean;
37
+ };
38
+
39
+ // Bounds on the queue between the runtime's delivery and the native applier. The runtime already
40
+ // chunks a delivery by records and estimated bytes; this caps how many chunks may wait.
41
+ const QUEUE_CAPACITY_BYTES = 64 * 1024 * 1024;
42
+ const APPLY_SLICE_MILLIS = 5;
43
+ const BARRIER_IDLE_MULTIPLE = 3;
44
+ const BARRIER_IDLE_CEILING_MILLISECONDS = 7_500;
45
+ // Writes to an index this far behind fail with a retryable 503 (see the runtime's lag policy).
46
+ const DEFAULT_MAX_LAG_MILLISECONDS = 30_000;
47
+
48
+ /**
49
+ * The native index methods the backend drives. `applyDerivedValue` inserts, replaces or removes
50
+ * one primary key's vector and stages its mapping as pending; `flushDerived` is the durability
51
+ * barrier that publishes the pending mappings; `resetDerivedStorage` destroys the native file.
52
+ */
53
+ export interface DerivedNativeIndex {
54
+ readonly indexStore: any;
55
+ applyDerivedValue(primaryKey: Id, vector: number[] | undefined, version?: number): void;
56
+ flushDerived(): Promise<void>;
57
+ resetDerivedStorage(): void;
58
+ assertDerivedValue(vector: unknown, label: string): void;
59
+ attachDerivedHost(host: DerivedNativeIndexHost): void;
60
+ }
61
+
62
+ /**
63
+ * `DerivedIndexBackend` over a file-primary HNSW index. `deliver()` only enqueues; an applier drains
64
+ * the queue in bounded time slices so a 4096-record chunk at ~0.35 ms per native insert does not
65
+ * hold the event loop for a second and a half. The barrier is the plane's `msync`, after which the
66
+ * pending mappings and then the cursor vector are published — in that order, so a crash between
67
+ * any two steps leaves a cursor that replays (idempotently) over a mapping that was never published,
68
+ * never a published cursor over native state the barrier did not cover.
69
+ */
70
+ export class HnswDerivedIndexBackend implements DerivedIndexBackend {
71
+ readonly id: string;
72
+ #index: DerivedNativeIndex;
73
+ #host?: DerivedIndexBackendHost;
74
+ #wake?: (change?: DerivedIndexBackendStateChange) => void;
75
+ #queue: DerivedIndexBatch[] = [];
76
+ #queuedBytes = 0;
77
+ #position = 0;
78
+ #scheduled = false;
79
+ #appliedCursor?: DerivedIndexCursor;
80
+ #appliedEpoch?: bigint;
81
+ #flushRequested = false;
82
+ #flushing?: Promise<void>;
83
+ #interruptBarrierAfter = 0;
84
+ #resetting?: Promise<void>;
85
+ #unindexable = 0;
86
+
87
+ constructor(id: string, index: DerivedNativeIndex) {
88
+ this.id = id;
89
+ this.#index = index;
90
+ }
91
+
92
+ attach(host: DerivedIndexBackendHost): void {
93
+ this.#host = host;
94
+ }
95
+
96
+ onStateChange(wake: (change?: DerivedIndexBackendStateChange) => void): () => void {
97
+ this.#wake = wake;
98
+ return () => {
99
+ if (this.#wake === wake) this.#wake = undefined;
100
+ };
101
+ }
102
+
103
+ getDurableCursor(): DerivedIndexCursor | undefined {
104
+ const cursor = this.#index.indexStore.getSync(DERIVED_INDEX_CURSOR_KEY);
105
+ return cursor === undefined ? undefined : (cursor as DerivedIndexCursor);
106
+ }
107
+
108
+ publishCoverage(positions: DerivedIndexPositions, ownerEpoch: bigint): void {
109
+ if (!this.#host?.isOwnerEpoch(ownerEpoch)) return;
110
+ const cursor = this.getDurableCursor();
111
+ if (!cursor) throw new Error('Cannot publish native index coverage without a durable cursor');
112
+ if (cursor.coverage && sameDerivedIndexPositions(cursor.coverage, positions)) return;
113
+ this.#index.indexStore.putSync(DERIVED_INDEX_CURSOR_KEY, { ...cursor, coverage: positions });
114
+ }
115
+
116
+ deliver(batch: DerivedIndexBatch): DerivedIndexDeliveryResult {
117
+ if (this.#queuedBytes >= QUEUE_CAPACITY_BYTES) return DERIVED_INDEX_DEFERRED;
118
+ this.#queue.push(batch);
119
+ this.#queuedBytes += batch.bytes;
120
+ this.#schedule();
121
+ return DERIVED_INDEX_ACCEPTED;
122
+ }
123
+
124
+ flush(_reason: DerivedIndexFlushReason): void {
125
+ this.#flushRequested = true;
126
+ if (this.#queue.length === 0 && !this.#scheduled) this.#runFlush();
127
+ }
128
+
129
+ /**
130
+ * Drop what is queued and resolve once no barrier is in flight. The runtime quiesces an epoch
131
+ * before it mints the next, so nothing of a newer epoch can be queued here yet.
132
+ */
133
+ async shutdown(_epoch: bigint): Promise<void> {
134
+ this.#dropQueue();
135
+ await Promise.allSettled([this.#flushing, this.#resetting]);
136
+ }
137
+
138
+ /**
139
+ * The cursor goes first: a crash anywhere after this line reopens cursorless and rebuilds, never
140
+ * on a format-valid cursor over a destroyed graph.
141
+ */
142
+ reset(_epoch: bigint): Promise<void> {
143
+ this.#dropQueue();
144
+ this.#appliedCursor = undefined;
145
+ this.#resetting = (async () => {
146
+ await this.#flushing;
147
+ this.#index.indexStore.removeSync(DERIVED_INDEX_CURSOR_KEY);
148
+ this.#index.resetDerivedStorage();
149
+ await this.#index.indexStore.clear();
150
+ })();
151
+ return this.#resetting.finally(() => (this.#resetting = undefined));
152
+ }
153
+
154
+ #dropQueue() {
155
+ this.#queue.length = 0;
156
+ this.#queuedBytes = 0;
157
+ this.#position = 0;
158
+ }
159
+
160
+ #schedule() {
161
+ if (this.#scheduled) return;
162
+ this.#scheduled = true;
163
+ setImmediate(() => {
164
+ this.#scheduled = false;
165
+ this.#applySlice();
166
+ });
167
+ }
168
+
169
+ #applySlice() {
170
+ // Application pauses while a barrier is in flight so the barrier publishes exactly the
171
+ // mappings it covers; the flush reschedules application when it settles.
172
+ if (this.#flushing) return;
173
+ const host = this.#host!;
174
+ const until = performance.now() + APPLY_SLICE_MILLIS;
175
+ const wasFull = this.#queuedBytes >= QUEUE_CAPACITY_BYTES;
176
+ let advancedCursor = false;
177
+ while (this.#queue.length > 0 && performance.now() < until) {
178
+ const batch = this.#queue[0];
179
+ if (!host.isOwnerEpoch(batch.ownerEpoch)) {
180
+ this.#queue.shift();
181
+ this.#queuedBytes -= batch.bytes;
182
+ this.#position = 0;
183
+ continue;
184
+ }
185
+ const records = batch.records;
186
+ while (this.#position < records.length && performance.now() < until) {
187
+ try {
188
+ this.#apply(records[this.#position++]);
189
+ } catch (error) {
190
+ this.#queue.length = 0;
191
+ this.#queuedBytes = 0;
192
+ this.#position = 0;
193
+ logger.error(`Derived index '${this.id}' could not apply a record; requesting a rebuild`, error);
194
+ this.#wake?.('failed');
195
+ return;
196
+ }
197
+ }
198
+ if (this.#position < records.length) break;
199
+ this.#queue.shift();
200
+ this.#queuedBytes -= batch.bytes;
201
+ this.#position = 0;
202
+ this.#appliedEpoch = batch.ownerEpoch;
203
+ if (batch.through) {
204
+ this.#appliedCursor = batch.through;
205
+ advancedCursor = true;
206
+ if (this.#mayInterruptForBarrier()) break;
207
+ }
208
+ }
209
+ if (this.#queue.length > 0) {
210
+ if (wasFull && this.#queuedBytes < QUEUE_CAPACITY_BYTES) this.#wake?.('changed');
211
+ if (this.#position === 0 && advancedCursor && this.#mayInterruptForBarrier()) this.#runFlush(true);
212
+ else this.#schedule();
213
+ return;
214
+ }
215
+ if (wasFull) this.#wake?.('changed');
216
+ if (this.#flushRequested) this.#runFlush();
217
+ }
218
+
219
+ #apply(mutation: DerivedIndexMutation) {
220
+ const { recordId, logVersion, state } = mutation;
221
+ if (state.kind !== 'record' || state.projection == null) {
222
+ this.#index.applyDerivedValue(recordId, undefined, logVersion);
223
+ return;
224
+ }
225
+ try {
226
+ this.#index.applyDerivedValue(recordId, state.projection as number[], state.version);
227
+ } catch (error) {
228
+ // The projection validated the vector, but the plane's dimensionality is only known to the
229
+ // worker holding it: a mismatch is this record's fault, not the index's. Same rule as the
230
+ // runtime's own 4xx handling — remove any entry and count it, never rebuild.
231
+ if (!(error instanceof ClientError)) throw error;
232
+ if (this.#unindexable++ === 0)
233
+ logger.warn?.(`Derived index '${this.id}' skipped a record its plane cannot hold: ${error.message}`);
234
+ this.#index.applyDerivedValue(recordId, undefined, state.version);
235
+ }
236
+ }
237
+
238
+ #mayInterruptForBarrier(): boolean {
239
+ return this.#flushRequested && performance.now() >= this.#interruptBarrierAfter;
240
+ }
241
+
242
+ #runFlush(interrupting = false) {
243
+ if (this.#flushing) return;
244
+ this.#flushRequested = false;
245
+ const started = performance.now();
246
+ const cursor = this.#appliedCursor;
247
+ const epoch = this.#appliedEpoch;
248
+ const host = this.#host!;
249
+ this.#flushing = (async () => {
250
+ await this.#index.flushDerived();
251
+ if (epoch !== undefined && !host.isOwnerEpoch(epoch)) return;
252
+ if (cursor) {
253
+ const coverage = this.getDurableCursor()?.coverage;
254
+ this.#index.indexStore.putSync(DERIVED_INDEX_CURSOR_KEY, coverage ? { ...cursor, coverage } : cursor);
255
+ }
256
+ })();
257
+ this.#flushing.then(
258
+ () => {
259
+ this.#flushing = undefined;
260
+ if (interrupting) {
261
+ const idle = Math.min(
262
+ BARRIER_IDLE_MULTIPLE * (performance.now() - started),
263
+ BARRIER_IDLE_CEILING_MILLISECONDS
264
+ );
265
+ this.#interruptBarrierAfter = performance.now() + idle;
266
+ }
267
+ this.#wake?.('changed');
268
+ if (this.#queue.length > 0) this.#schedule();
269
+ else if (this.#flushRequested) this.#runFlush();
270
+ },
271
+ (error) => {
272
+ this.#flushing = undefined;
273
+ logger.error(`Derived index '${this.id}' durability barrier failed`, error);
274
+ this.#wake?.('failed');
275
+ }
276
+ );
277
+ }
278
+ }
279
+
280
+ // One generation owns each physical backend; destructive cleanup also awaits superseded generations.
281
+ type RegisteredTable = { current: { Table: any }; owners: Set<{ Table: any }> };
282
+ type RegisteredBackend = {
283
+ tableId: number;
284
+ settle: () => Promise<void>;
285
+ };
286
+ type Registered = {
287
+ runtime: DerivedIndexRuntime;
288
+ tables: Map<number, RegisteredTable>;
289
+ backends: Map<string, RegisteredBackend>;
290
+ tableBackends: Map<number, Set<RegisteredBackend>>;
291
+ droppingTables: Set<number>;
292
+ retryUnavailable: Set<string>;
293
+ };
294
+ const runtimes = new WeakMap<object, Registered>();
295
+ const retryUnavailableByStore = new Set<string>();
296
+
297
+ function retryUnavailableKey(auditStore: RocksTransactionLogStore, backendId: string): string {
298
+ return `${auditStore.rootStore.path}\0${backendId}`;
299
+ }
300
+
301
+ function markUnavailableRetry(registered: Registered, auditStore: RocksTransactionLogStore, backendId: string): void {
302
+ registered.retryUnavailable.add(backendId);
303
+ retryUnavailableByStore.add(retryUnavailableKey(auditStore, backendId));
304
+ }
305
+
306
+ function consumeUnavailableRetry(
307
+ registered: Registered,
308
+ auditStore: RocksTransactionLogStore,
309
+ backendId: string
310
+ ): boolean {
311
+ const local = registered.retryUnavailable.delete(backendId);
312
+ const storeScoped = retryUnavailableByStore.delete(retryUnavailableKey(auditStore, backendId));
313
+ return local || storeScoped;
314
+ }
315
+
316
+ function runtimeFor(auditStore: RocksTransactionLogStore): Registered {
317
+ let registered = runtimes.get(auditStore);
318
+ if (registered) return registered;
319
+ const tables = new Map<number, RegisteredTable>();
320
+ const runtime = new DerivedIndexRuntime(
321
+ auditStore,
322
+ (tableId, recordId) => {
323
+ const entry = tables.get(tableId)?.current.Table.primaryStore.getEntry(recordId);
324
+ return entry?.value == null ? undefined : { version: entry.version, value: entry.value };
325
+ },
326
+ {
327
+ scanRecords: (tableId) =>
328
+ tables
329
+ .get(tableId)!
330
+ .current.Table.primaryStore.getRange({ versions: true, snapshot: false })
331
+ .map(({ key, value, version }) => ({ recordId: key, version, value })),
332
+ }
333
+ );
334
+ registered = {
335
+ runtime,
336
+ tables,
337
+ backends: new Map(),
338
+ tableBackends: new Map(),
339
+ droppingTables: new Set(),
340
+ retryUnavailable: new Set(),
341
+ };
342
+ runtimes.set(auditStore, registered);
343
+ return registered;
344
+ }
345
+
346
+ const warnedAuditIndexes = new Set<string>();
347
+
348
+ /**
349
+ * Register every post-commit custom index of a table with the shared derived-index runtime of its
350
+ * database. Returns the release for the table's registrations, or undefined when it has none. Runs
351
+ * on every worker; the runtime elects one owner per index.
352
+ */
353
+ export function attachDerivedIndexes(Table: any):
354
+ | {
355
+ close(dropping?: boolean): Promise<void>;
356
+ restoreAfterFailedDrop(): ReturnType<typeof attachDerivedIndexes>;
357
+ completeDrop(dropped?: boolean): void;
358
+ }
359
+ | undefined {
360
+ const hnswAttributes = Table.attributes.filter(
361
+ (attribute: any) => attribute.indexed?.type === 'HNSW' && Table.indices[attribute.name]?.customIndex
362
+ );
363
+ const attributes = hnswAttributes.filter((attribute: any) => Table.indices[attribute.name]?.customIndex?.postCommit);
364
+ if (Table.audit !== true && attributes.length > 0) {
365
+ throw new ClientError(
366
+ `Table '${Table.databaseName}.${Table.tableName}' must enable audit logging before using a post-commit derived index`
367
+ );
368
+ }
369
+ if (!Table.auditStore) return;
370
+ const auditStore = Table.auditStore as RocksTransactionLogStore;
371
+ const registered = runtimeFor(auditStore);
372
+ if (registered.droppingTables.has(Table.tableId)) return;
373
+ for (const attribute of hnswAttributes) {
374
+ const indexStore = Table.indices[attribute.name];
375
+ const id = `hnsw:${indexStore.name}`;
376
+ // A transient JS-backed declaration can precede the first native registration while a
377
+ // schema is being installed. Only an explicit transition away from an already-registered
378
+ // native backend should make a later native registration eligible to rearm an exhausted
379
+ // rebuild budget.
380
+ if (attribute.indexed.nativePlane === false && !indexStore.customIndex.postCommit && registered.backends.has(id))
381
+ markUnavailableRetry(registered, auditStore, id);
382
+ }
383
+ if (attributes.length === 0) return;
384
+ const installed = { Table };
385
+ let registeredTable = registered.tables.get(Table.tableId);
386
+ if (registeredTable) {
387
+ registeredTable.owners.add(installed);
388
+ registeredTable.current = installed;
389
+ } else {
390
+ registeredTable = { current: installed, owners: new Set([installed]) };
391
+ registered.tables.set(Table.tableId, registeredTable);
392
+ }
393
+ const releases: Array<() => Promise<void>> = [];
394
+ const backendIds: string[] = [];
395
+ const registeredBackends = new Map<string, RegisteredBackend>();
396
+ for (const attribute of attributes) {
397
+ const indexStore = Table.indices[attribute.name];
398
+ const index = indexStore.customIndex as DerivedNativeIndex & { postCommit: true };
399
+ const id = `hnsw:${indexStore.name}`;
400
+ const warningKey = `${Table.databaseName}.${Table.tableName}.${indexStore.name}`;
401
+ if (!warnedAuditIndexes.has(warningKey)) {
402
+ warnedAuditIndexes.add(warningKey);
403
+ logger.warn?.(
404
+ `Derived index ${indexStore.name} requires auditing; the audit API retains full record history for the configured retention window`
405
+ );
406
+ }
407
+ const resolver = Table.propertyResolvers?.[attribute.name];
408
+ const label = `Vector for attribute "${attribute.name}"`;
409
+ index.attachDerivedHost({
410
+ readiness: () => registered.runtime.getReadiness(id),
411
+ coverage: (maxLagMilliseconds) =>
412
+ readDerivedIndexCoverage(
413
+ auditStore,
414
+ id,
415
+ () => indexStore.getSync(DERIVED_INDEX_CURSOR_KEY),
416
+ maxLagMilliseconds
417
+ ),
418
+ requestRebuild: () => registered.runtime.requestRebuild(id),
419
+ waitForCoverage: (since, timeout, signal) => registered.runtime.waitForCoverage(id, since, timeout, signal),
420
+ });
421
+ let predecessor = registered.backends.get(id);
422
+ const inherited = predecessor;
423
+ const settlePredecessor = () => {
424
+ const current = predecessor;
425
+ if (!current) return Promise.resolve();
426
+ const settled = current.settle();
427
+ settled.then(
428
+ () => {
429
+ if (predecessor === current) predecessor = undefined;
430
+ },
431
+ () => {}
432
+ );
433
+ return settled;
434
+ };
435
+ const predecessorSettled = settlePredecessor();
436
+ predecessorSettled.catch(() => {});
437
+ if (registered.backends.get(id) === inherited) registered.backends.delete(id);
438
+ const release = registered.runtime.register({
439
+ backend: new HnswDerivedIndexBackend(id, index),
440
+ projections: new Map([
441
+ [
442
+ Table.tableId,
443
+ (record: any) => {
444
+ const vector = resolver ? resolver(record) : record[attribute.name];
445
+ if (vector == null) return undefined;
446
+ index.assertDerivedValue(vector, label);
447
+ return vector;
448
+ },
449
+ ],
450
+ ]),
451
+ options: { maxLagMilliseconds: attribute.indexed?.maxLagMilliseconds ?? DEFAULT_MAX_LAG_MILLISECONDS },
452
+ });
453
+ let settling: Promise<void> | undefined;
454
+ const registeredBackend: RegisteredBackend = {
455
+ tableId: Table.tableId,
456
+ settle: () => {
457
+ if (settling) return settling;
458
+ const attempt = Promise.allSettled([settlePredecessor(), release()]).then((results) => {
459
+ if (results[1].status === 'fulfilled') {
460
+ if (registered.backends.get(id) === registeredBackend) registered.backends.delete(id);
461
+ const tableBackends = registered.tableBackends.get(Table.tableId);
462
+ tableBackends?.delete(registeredBackend);
463
+ if (tableBackends?.size === 0) registered.tableBackends.delete(Table.tableId);
464
+ }
465
+ const failures = results
466
+ .filter((result): result is PromiseRejectedResult => result.status === 'rejected')
467
+ .map((result) => result.reason);
468
+ if (failures.length === 1) throw failures[0];
469
+ if (failures.length) throw new AggregateError(failures, `Could not settle HNSW backend '${id}'`);
470
+ });
471
+ settling = attempt;
472
+ attempt.catch(() => {
473
+ if (settling === attempt) settling = undefined;
474
+ });
475
+ return attempt;
476
+ },
477
+ };
478
+ let tableBackends = registered.tableBackends.get(Table.tableId);
479
+ if (!tableBackends) registered.tableBackends.set(Table.tableId, (tableBackends = new Set()));
480
+ tableBackends.add(registeredBackend);
481
+ registered.backends.set(id, registeredBackend);
482
+ registeredBackends.set(id, registeredBackend);
483
+ const retryUnavailable = consumeUnavailableRetry(registered, auditStore, id);
484
+ if (retryUnavailable && registered.runtime.getReadiness(id).state === 'unavailable')
485
+ registered.runtime.requestRebuild(id);
486
+ backendIds.push(id);
487
+ releases.push(() => registeredBackend.settle());
488
+ }
489
+ return {
490
+ async close(dropping = false) {
491
+ if (dropping) registered.droppingTables.add(Table.tableId);
492
+ const settlements = dropping
493
+ ? [...(registered.tableBackends.get(Table.tableId) ?? [])].map((backend) => backend.settle())
494
+ : releases.map((release) => release());
495
+ const tableRegistration = registered.tables.get(Table.tableId);
496
+ if (tableRegistration) {
497
+ tableRegistration.owners.delete(installed);
498
+ if (tableRegistration.owners.size === 0) {
499
+ registered.tables.delete(Table.tableId);
500
+ } else if (tableRegistration.current === installed) {
501
+ tableRegistration.current = tableRegistration.owners.values().next().value;
502
+ }
503
+ }
504
+ if (dropping) {
505
+ await Promise.all(settlements);
506
+ } else {
507
+ for (const result of await Promise.allSettled(settlements)) {
508
+ if (result.status === 'rejected')
509
+ logger.error(`Could not settle a superseded HNSW backend for table ${Table.tableId}`, result.reason);
510
+ }
511
+ }
512
+ },
513
+ restoreAfterFailedDrop() {
514
+ registered.droppingTables.delete(Table.tableId);
515
+ for (const [id, registeredBackend] of registeredBackends) {
516
+ const current = registered.backends.get(id);
517
+ if (current && current !== registeredBackend) return;
518
+ }
519
+ return attachDerivedIndexes(Table);
520
+ },
521
+ completeDrop(dropped = true) {
522
+ registered.droppingTables.delete(Table.tableId);
523
+ if (dropped) for (const id of backendIds) markUnavailableRetry(registered, auditStore, id);
524
+ },
525
+ };
526
+ }
527
+
528
+ /** Shared readiness of an index on any worker, registered or not. */
529
+ export function derivedIndexReadiness(auditStore: RocksTransactionLogStore, indexStoreName: string) {
530
+ return readDerivedIndexReadiness(auditStore, `hnsw:${indexStoreName}`);
531
+ }
@@ -0,0 +1,174 @@
1
+ import { closeSync, fsyncSync, openSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { loggerWithTag } from '../../utility/logging/logger.ts';
4
+
5
+ const logger = loggerWithTag('HNSW');
6
+
7
+ /**
8
+ * Parallel arrays, ascending by distance: hit i is (ids[i], distances[i]) with its host key at
9
+ * keys.subarray(keyEnds[i - 1] ?? 0, keyEnds[i]); an empty key means the node vanished mid-query.
10
+ */
11
+ export interface PlaneSearchHits {
12
+ ids: Uint32Array;
13
+ distances: Float32Array;
14
+ keys: Buffer;
15
+ keyEnds: Uint32Array;
16
+ }
17
+
18
+ /** A predicate batch: candidate ids and their host keys, laid out as in PlaneSearchHits. */
19
+ export type PlanePredicate = (ids: number[], keys: Buffer, keyEnds: Uint32Array) => Uint8Array;
20
+
21
+ /** NAPI surface of the native file-primary HNSW index (`@harperfast/hnsw`). */
22
+ export interface HnswPlane {
23
+ readonly dims: number;
24
+ readonly layer0Cap: number;
25
+ readonly keyCap: number;
26
+ insert(vector: Float32Array, key?: Buffer): number;
27
+ remove(id: number): void;
28
+ writeNodeRaw(
29
+ id: number,
30
+ level: number,
31
+ vector: Buffer,
32
+ scale: number,
33
+ invMag: number,
34
+ neighbors: Uint32Array,
35
+ upper: Uint32Array[] | null
36
+ ): void;
37
+ clearNode(id: number): void;
38
+ setEntryPoint(id: number, level: number): void;
39
+ getEntryPoint(): number[];
40
+ search(
41
+ vector: Float32Array,
42
+ k: number,
43
+ ef: number,
44
+ filter?: Uint8Array | null,
45
+ filterExpansion?: number | null
46
+ ): Promise<PlaneSearchHits>;
47
+ searchWithPredicate(
48
+ vector: Float32Array,
49
+ k: number,
50
+ ef: number,
51
+ predicate: PlanePredicate,
52
+ filterExpansion?: number | null,
53
+ visitBudget?: number | null
54
+ ): Promise<PlaneSearchHits>;
55
+ searchSync(vector: Float32Array, k: number, ef: number): PlaneSearchHits;
56
+ writeNodeRawIfAbsent(
57
+ id: number,
58
+ level: number,
59
+ vector: Buffer,
60
+ scale: number,
61
+ invMag: number,
62
+ neighbors: Uint32Array,
63
+ upper: Uint32Array[] | null
64
+ ): boolean;
65
+ openedClean(): boolean;
66
+ idHighWater(): number;
67
+ getWatermark(): number;
68
+ setWatermark(txn: number): void;
69
+ flush(watermark?: number): void;
70
+ flushAsync(watermark?: number): Promise<void>;
71
+ invalidateFile(): PlaneInvalidationOutcome;
72
+ invalidated(): boolean;
73
+ }
74
+
75
+ export interface HnswPlaneConstructor {
76
+ readonly prototype: HnswPlane;
77
+ create(path: string, dims: number, layer0Cap: number, maxNodes: number, keyCap?: number): HnswPlane;
78
+ open(path: string): HnswPlane;
79
+ }
80
+
81
+ export interface PlaneInvalidationOutcome {
82
+ inBand: boolean;
83
+ sidecar: boolean;
84
+ inBandError?: string;
85
+ sidecarError?: string;
86
+ }
87
+
88
+ interface HnswPlanePackage {
89
+ Plane: HnswPlaneConstructor;
90
+ invalidatePlane(path: string): PlaneInvalidationOutcome;
91
+ stalePathFor(path: string): string;
92
+ }
93
+
94
+ /** Entry-point id meaning "none" (u32::MAX in the plane header). */
95
+ export const PLANE_NO_ID = 0xffffffff;
96
+
97
+ /**
98
+ * Where an index's plane file lives: next to its store, named by the dbiKey
99
+ * (`table/attribute`, flattened to a single file name). Exposed separately from the index
100
+ * instance so crash-recovery drop paths can remove the file without opening the index.
101
+ */
102
+ export function planeFilePathFor(storePath: string, storeName: string): string {
103
+ // encodeURIComponent is injective and never emits a path separator: table `a` attribute
104
+ // `b.c` and table `a.b` attribute `c` must not share a plane file (dot-flattening let two
105
+ // indexes serve each other's node ids as their own primary keys)
106
+ return join(storePath, `${encodeURIComponent(storeName)}.hnsw`);
107
+ }
108
+
109
+ /**
110
+ * Tombstone marking a plane file that could not be deleted (e.g. Windows EBUSY while still
111
+ * mapped). Its presence means the plane file is STALE: never open it — delete both when
112
+ * possible and rebuild.
113
+ */
114
+ export function planeStalePathFor(planePath: string): string {
115
+ // the package owns the convention; the literal covers the calls that precede its load
116
+ return binding?.stalePathFor(planePath) ?? `${planePath}.stale`;
117
+ }
118
+
119
+ let binding: HnswPlanePackage | null | undefined;
120
+ let bindingLoadError: Error | undefined;
121
+ let bindingWarningLogged = false;
122
+
123
+ function getHnswPackage(warn = true): HnswPlanePackage | null {
124
+ if (binding === undefined) {
125
+ try {
126
+ binding = require('@harperfast/hnsw') as HnswPlanePackage;
127
+ } catch (error) {
128
+ binding = null;
129
+ bindingLoadError = error as Error;
130
+ }
131
+ }
132
+ if (binding === null && warn && !bindingWarningLogged) {
133
+ bindingWarningLogged = true;
134
+ logger.warn?.(
135
+ `The @harperfast/hnsw native module is not available (${bindingLoadError?.message}); ` +
136
+ 'indexes with nativePlane enabled will remain unavailable until the module can load'
137
+ );
138
+ }
139
+ return binding;
140
+ }
141
+
142
+ /** The native plane constructor, or null when the compiled artifact is unavailable (warns once by default). */
143
+ export function getPlaneBinding(warn = true): HnswPlaneConstructor | null {
144
+ return getHnswPackage(warn)?.Plane ?? null;
145
+ }
146
+
147
+ /** Make a derived plane unadoptable before it is replaced or removed. */
148
+ export function invalidatePlaneFile(filePath: string, attached?: HnswPlane | null): PlaneInvalidationOutcome {
149
+ if (attached) return attached.invalidateFile();
150
+ const hnswPackage = getHnswPackage();
151
+ if (hnswPackage) return hnswPackage.invalidatePlane(filePath);
152
+ // A plane can outlive the package that made it (uninstall, or a prebuild that stopped
153
+ // loading), and a reinstall would then adopt it. Only the sidecar is reachable without the
154
+ // package, and it has to survive a power loss to be worth writing, so fsync it and the
155
+ // directory entry that names it — the same durability the package's own sidecar has.
156
+ const fd = openSync(planeStalePathFor(filePath), 'w');
157
+ try {
158
+ fsyncSync(fd);
159
+ } finally {
160
+ closeSync(fd);
161
+ }
162
+ try {
163
+ const dirFd = openSync(dirname(filePath), 'r');
164
+ try {
165
+ fsyncSync(dirFd);
166
+ } finally {
167
+ closeSync(dirFd);
168
+ }
169
+ } catch {
170
+ // Windows cannot open a directory as a file; it also does not need this — the metadata
171
+ // journal already orders the create ahead of anything that could read the sidecar
172
+ }
173
+ return { inBand: false, sidecar: true };
174
+ }