@harperfast/harper 5.2.9 → 5.3.0-alpha.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 (668) hide show
  1. package/agent/mcpTools.ts +1 -1
  2. package/agent/session.ts +25 -14
  3. package/bin/cliOperations.ts +46 -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 +59 -3
  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 +2414 -242
  14. package/components/ApplicationScope.ts +8 -0
  15. package/components/EntryHandler.ts +59 -39
  16. package/components/OptionsWatcher.ts +150 -74
  17. package/components/RuntimeModuleTracker.ts +38 -7
  18. package/components/Scope.ts +37 -15
  19. package/components/awaitRestart.ts +84 -0
  20. package/components/componentLoader.ts +340 -30
  21. package/components/componentPreparationLock.ts +16 -5
  22. package/components/mcp/adapters/harperHttp.ts +4 -0
  23. package/components/mcp/listChanged.ts +4 -0
  24. package/components/mcp/toolRegistry.ts +2 -0
  25. package/components/mcp/tools/operations.ts +9 -0
  26. package/components/mcp/tools/schemas/operationDescriptions.ts +2 -2
  27. package/components/operations.js +270 -78
  28. package/components/operationsValidation.js +49 -1
  29. package/components/status/ComponentStatusRegistry.ts +59 -0
  30. package/config/RootConfigWatcher.ts +80 -34
  31. package/config/configUtils.ts +291 -34
  32. package/config/harperConfigEnvVars.ts +170 -27
  33. package/config-root.schema.json +29 -0
  34. package/dataLayer/blobBackup.ts +160 -50
  35. package/dataLayer/delete.ts +6 -1
  36. package/dataLayer/harperBridge/ResourceBridge.ts +52 -8
  37. package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
  38. package/dataLayer/hdbInfoController.ts +34 -1
  39. package/dataLayer/insert.ts +44 -1
  40. package/dataLayer/rocksdbBackup.ts +53 -10
  41. package/dataLayer/schema.ts +11 -1
  42. package/dataLayer/schemaDescribe.ts +8 -1
  43. package/dist/agent/mcpTools.js +1 -1
  44. package/dist/agent/mcpTools.js.map +1 -1
  45. package/dist/agent/session.d.ts +22 -0
  46. package/dist/agent/session.js +26 -15
  47. package/dist/agent/session.js.map +1 -1
  48. package/dist/bin/cliOperations.js +48 -9
  49. package/dist/bin/cliOperations.js.map +1 -1
  50. package/dist/bin/copyDb.d.ts +12 -1
  51. package/dist/bin/copyDb.js +248 -60
  52. package/dist/bin/copyDb.js.map +1 -1
  53. package/dist/bin/deploySetup.d.ts +2 -0
  54. package/dist/bin/deploySetup.js +11 -3
  55. package/dist/bin/deploySetup.js.map +1 -1
  56. package/dist/bin/harper.js +1 -1
  57. package/dist/bin/harper.js.map +1 -1
  58. package/dist/bin/help.js +4 -1
  59. package/dist/bin/help.js.map +1 -1
  60. package/dist/bin/lite.js +4 -1
  61. package/dist/bin/lite.js.map +1 -1
  62. package/dist/bin/restart.js +54 -5
  63. package/dist/bin/restart.js.map +1 -1
  64. package/dist/bin/run.js +4 -10
  65. package/dist/bin/run.js.map +1 -1
  66. package/dist/bin/upgrade.js +4 -3
  67. package/dist/bin/upgrade.js.map +1 -1
  68. package/dist/bin/workloadIdentity.d.ts +18 -0
  69. package/dist/bin/workloadIdentity.js +100 -0
  70. package/dist/bin/workloadIdentity.js.map +1 -0
  71. package/dist/components/Application.d.ts +139 -16
  72. package/dist/components/Application.js +2215 -267
  73. package/dist/components/Application.js.map +1 -1
  74. package/dist/components/ApplicationScope.d.ts +8 -0
  75. package/dist/components/ApplicationScope.js +7 -0
  76. package/dist/components/ApplicationScope.js.map +1 -1
  77. package/dist/components/EntryHandler.js +26 -10
  78. package/dist/components/EntryHandler.js.map +1 -1
  79. package/dist/components/OptionsWatcher.d.ts +1 -0
  80. package/dist/components/OptionsWatcher.js +141 -74
  81. package/dist/components/OptionsWatcher.js.map +1 -1
  82. package/dist/components/RuntimeModuleTracker.js +40 -6
  83. package/dist/components/RuntimeModuleTracker.js.map +1 -1
  84. package/dist/components/Scope.js +38 -13
  85. package/dist/components/Scope.js.map +1 -1
  86. package/dist/components/awaitRestart.d.ts +33 -0
  87. package/dist/components/awaitRestart.js +61 -0
  88. package/dist/components/awaitRestart.js.map +1 -0
  89. package/dist/components/componentLoader.d.ts +38 -1
  90. package/dist/components/componentLoader.js +279 -22
  91. package/dist/components/componentLoader.js.map +1 -1
  92. package/dist/components/componentPreparationLock.d.ts +5 -0
  93. package/dist/components/componentPreparationLock.js +14 -6
  94. package/dist/components/componentPreparationLock.js.map +1 -1
  95. package/dist/components/mcp/adapters/harperHttp.js +4 -0
  96. package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
  97. package/dist/components/mcp/listChanged.js +5 -0
  98. package/dist/components/mcp/listChanged.js.map +1 -1
  99. package/dist/components/mcp/toolRegistry.d.ts +1 -0
  100. package/dist/components/mcp/toolRegistry.js.map +1 -1
  101. package/dist/components/mcp/tools/operations.d.ts +5 -0
  102. package/dist/components/mcp/tools/operations.js +9 -0
  103. package/dist/components/mcp/tools/operations.js.map +1 -1
  104. package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -2
  105. package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
  106. package/dist/components/operations.js +231 -77
  107. package/dist/components/operations.js.map +1 -1
  108. package/dist/components/operationsValidation.js +49 -1
  109. package/dist/components/operationsValidation.js.map +1 -1
  110. package/dist/components/status/ComponentStatusRegistry.d.ts +0 -4
  111. package/dist/components/status/ComponentStatusRegistry.js +63 -0
  112. package/dist/components/status/ComponentStatusRegistry.js.map +1 -1
  113. package/dist/config/RootConfigWatcher.d.ts +7 -1
  114. package/dist/config/RootConfigWatcher.js +64 -27
  115. package/dist/config/RootConfigWatcher.js.map +1 -1
  116. package/dist/config/configUtils.d.ts +9 -1
  117. package/dist/config/configUtils.js +254 -33
  118. package/dist/config/configUtils.js.map +1 -1
  119. package/dist/config/harperConfigEnvVars.d.ts +16 -0
  120. package/dist/config/harperConfigEnvVars.js +162 -25
  121. package/dist/config/harperConfigEnvVars.js.map +1 -1
  122. package/dist/dataLayer/blobBackup.d.ts +49 -20
  123. package/dist/dataLayer/blobBackup.js +139 -50
  124. package/dist/dataLayer/blobBackup.js.map +1 -1
  125. package/dist/dataLayer/delete.js +1 -1
  126. package/dist/dataLayer/delete.js.map +1 -1
  127. package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +14 -1
  128. package/dist/dataLayer/harperBridge/ResourceBridge.js +51 -10
  129. package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
  130. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.d.ts +3 -1
  131. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
  132. package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js.map +1 -1
  133. package/dist/dataLayer/hdbInfoController.d.ts +10 -0
  134. package/dist/dataLayer/hdbInfoController.js +30 -1
  135. package/dist/dataLayer/hdbInfoController.js.map +1 -1
  136. package/dist/dataLayer/insert.d.ts +9 -1
  137. package/dist/dataLayer/insert.js +30 -0
  138. package/dist/dataLayer/insert.js.map +1 -1
  139. package/dist/dataLayer/rocksdbBackup.d.ts +2 -2
  140. package/dist/dataLayer/rocksdbBackup.js +45 -8
  141. package/dist/dataLayer/rocksdbBackup.js.map +1 -1
  142. package/dist/dataLayer/schema.js +8 -0
  143. package/dist/dataLayer/schema.js.map +1 -1
  144. package/dist/dataLayer/schemaDescribe.js +8 -1
  145. package/dist/dataLayer/schemaDescribe.js.map +1 -1
  146. package/dist/index.d.ts +1 -1
  147. package/dist/index.js.map +1 -1
  148. package/dist/json/systemSchema.json +52 -0
  149. package/dist/resources/DatabaseTransaction.d.ts +55 -0
  150. package/dist/resources/DatabaseTransaction.js +459 -45
  151. package/dist/resources/DatabaseTransaction.js.map +1 -1
  152. package/dist/resources/LMDBTransaction.js +22 -4
  153. package/dist/resources/LMDBTransaction.js.map +1 -1
  154. package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
  155. package/dist/resources/PrimaryRocksDatabase.js +29 -0
  156. package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
  157. package/dist/resources/RecordEncoder.d.ts +20 -0
  158. package/dist/resources/RecordEncoder.js +94 -9
  159. package/dist/resources/RecordEncoder.js.map +1 -1
  160. package/dist/resources/RequestTarget.d.ts +2 -0
  161. package/dist/resources/RequestTarget.js.map +1 -1
  162. package/dist/resources/Resource.js +20 -11
  163. package/dist/resources/Resource.js.map +1 -1
  164. package/dist/resources/ResourceInterface.d.ts +20 -1
  165. package/dist/resources/ResourceInterface.js.map +1 -1
  166. package/dist/resources/RocksIndexStore.d.ts +6 -1
  167. package/dist/resources/RocksIndexStore.js +24 -9
  168. package/dist/resources/RocksIndexStore.js.map +1 -1
  169. package/dist/resources/RocksTransactionLogStore.d.ts +14 -1
  170. package/dist/resources/RocksTransactionLogStore.js +57 -17
  171. package/dist/resources/RocksTransactionLogStore.js.map +1 -1
  172. package/dist/resources/Table.d.ts +112 -8
  173. package/dist/resources/Table.js +1073 -191
  174. package/dist/resources/Table.js.map +1 -1
  175. package/dist/resources/auditStore.d.ts +11 -2
  176. package/dist/resources/auditStore.js +325 -71
  177. package/dist/resources/auditStore.js.map +1 -1
  178. package/dist/resources/blob.d.ts +129 -9
  179. package/dist/resources/blob.js +992 -114
  180. package/dist/resources/blob.js.map +1 -1
  181. package/dist/resources/branchDatabase.d.ts +48 -0
  182. package/dist/resources/branchDatabase.js +892 -0
  183. package/dist/resources/branchDatabase.js.map +1 -0
  184. package/dist/resources/crdt.js +50 -12
  185. package/dist/resources/crdt.js.map +1 -1
  186. package/dist/resources/databases.d.ts +150 -0
  187. package/dist/resources/databases.js +1200 -239
  188. package/dist/resources/databases.js.map +1 -1
  189. package/dist/resources/defineTable.d.ts +10 -2
  190. package/dist/resources/defineTable.js +9 -1
  191. package/dist/resources/defineTable.js.map +1 -1
  192. package/dist/resources/graphql.d.ts +1 -1
  193. package/dist/resources/graphql.js +50 -15
  194. package/dist/resources/graphql.js.map +1 -1
  195. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +1 -0
  196. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +6 -2
  197. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
  198. package/dist/resources/longLivedTransactions.d.ts +71 -0
  199. package/dist/resources/longLivedTransactions.js +358 -0
  200. package/dist/resources/longLivedTransactions.js.map +1 -0
  201. package/dist/resources/models/backendRegistry.d.ts +26 -0
  202. package/dist/resources/models/backendRegistry.js +60 -2
  203. package/dist/resources/models/backendRegistry.js.map +1 -1
  204. package/dist/resources/models/bootstrap.d.ts +33 -1
  205. package/dist/resources/models/bootstrap.js +416 -31
  206. package/dist/resources/models/bootstrap.js.map +1 -1
  207. package/dist/resources/recordLock.d.ts +80 -0
  208. package/dist/resources/recordLock.js +184 -0
  209. package/dist/resources/recordLock.js.map +1 -0
  210. package/dist/resources/replayLogs.d.ts +14 -1
  211. package/dist/resources/replayLogs.js +152 -24
  212. package/dist/resources/replayLogs.js.map +1 -1
  213. package/dist/resources/replayLogsGuards.d.ts +94 -7
  214. package/dist/resources/replayLogsGuards.js +111 -7
  215. package/dist/resources/replayLogsGuards.js.map +1 -1
  216. package/dist/resources/search.js +158 -6
  217. package/dist/resources/search.js.map +1 -1
  218. package/dist/resources/transactionBroadcast.d.ts +1 -1
  219. package/dist/resources/transactionBroadcast.js +2 -2
  220. package/dist/resources/transactionBroadcast.js.map +1 -1
  221. package/dist/security/auth.js +61 -30
  222. package/dist/security/auth.js.map +1 -1
  223. package/dist/security/authn/oidc/claims.d.ts +22 -0
  224. package/dist/security/authn/oidc/claims.js +71 -0
  225. package/dist/security/authn/oidc/claims.js.map +1 -0
  226. package/dist/security/authn/oidc/identityToken.d.ts +27 -0
  227. package/dist/security/authn/oidc/identityToken.js +111 -0
  228. package/dist/security/authn/oidc/identityToken.js.map +1 -0
  229. package/dist/security/authn/oidc/jwks.d.ts +25 -0
  230. package/dist/security/authn/oidc/jwks.js +261 -0
  231. package/dist/security/authn/oidc/jwks.js.map +1 -0
  232. package/dist/security/authn/oidc/providers/generic.d.ts +13 -0
  233. package/dist/security/authn/oidc/providers/generic.js +34 -0
  234. package/dist/security/authn/oidc/providers/generic.js.map +1 -0
  235. package/dist/security/authn/oidc/providers/githubActions.d.ts +11 -0
  236. package/dist/security/authn/oidc/providers/githubActions.js +129 -0
  237. package/dist/security/authn/oidc/providers/githubActions.js.map +1 -0
  238. package/dist/security/authn/oidc/providers/index.d.ts +37 -0
  239. package/dist/security/authn/oidc/providers/index.js +24 -0
  240. package/dist/security/authn/oidc/providers/index.js.map +1 -0
  241. package/dist/security/authn/oidc/tokenExchange.d.ts +12 -0
  242. package/dist/security/authn/oidc/tokenExchange.js +306 -0
  243. package/dist/security/authn/oidc/tokenExchange.js.map +1 -0
  244. package/dist/security/authn/oidc/trustPolicyOperations.d.ts +49 -0
  245. package/dist/security/authn/oidc/trustPolicyOperations.js +358 -0
  246. package/dist/security/authn/oidc/trustPolicyOperations.js.map +1 -0
  247. package/dist/security/authn/oidc/types.d.ts +38 -0
  248. package/dist/security/authn/oidc/types.js +6 -0
  249. package/dist/security/authn/oidc/types.js.map +1 -0
  250. package/dist/security/certificateVerification/index.js +40 -11
  251. package/dist/security/certificateVerification/index.js.map +1 -1
  252. package/dist/security/certificateVerification/trustedIssuers.d.ts +24 -0
  253. package/dist/security/certificateVerification/trustedIssuers.js +79 -0
  254. package/dist/security/certificateVerification/trustedIssuers.js.map +1 -0
  255. package/dist/security/certificateVerification/types.d.ts +1 -0
  256. package/dist/security/credentialProvenance.d.ts +35 -0
  257. package/dist/security/credentialProvenance.js +51 -0
  258. package/dist/security/credentialProvenance.js.map +1 -0
  259. package/dist/security/credentialRejection.d.ts +4 -0
  260. package/dist/security/credentialRejection.js +24 -0
  261. package/dist/security/credentialRejection.js.map +1 -0
  262. package/dist/security/deferredAuthentication.d.ts +36 -0
  263. package/dist/security/deferredAuthentication.js +70 -0
  264. package/dist/security/deferredAuthentication.js.map +1 -0
  265. package/dist/security/impersonation.d.ts +21 -0
  266. package/dist/security/impersonation.js +108 -9
  267. package/dist/security/impersonation.js.map +1 -1
  268. package/dist/security/jsLoader.d.ts +6 -0
  269. package/dist/security/jsLoader.js +75 -15
  270. package/dist/security/jsLoader.js.map +1 -1
  271. package/dist/security/keys.js +301 -71
  272. package/dist/security/keys.js.map +1 -1
  273. package/dist/security/operationScope.d.ts +21 -0
  274. package/dist/security/operationScope.js +36 -0
  275. package/dist/security/operationScope.js.map +1 -0
  276. package/dist/security/permissionsTranslator.js +21 -0
  277. package/dist/security/permissionsTranslator.js.map +1 -1
  278. package/dist/security/tokenAuthentication.d.ts +19 -1
  279. package/dist/security/tokenAuthentication.js +191 -10
  280. package/dist/security/tokenAuthentication.js.map +1 -1
  281. package/dist/security/user.js +4 -3
  282. package/dist/security/user.js.map +1 -1
  283. package/dist/server/DurableSubscriptionsSession.d.ts +2 -2
  284. package/dist/server/DurableSubscriptionsSession.js +67 -10
  285. package/dist/server/DurableSubscriptionsSession.js.map +1 -1
  286. package/dist/server/REST.js +73 -0
  287. package/dist/server/REST.js.map +1 -1
  288. package/dist/server/graphqlQuerying.js +4 -0
  289. package/dist/server/graphqlQuerying.js.map +1 -1
  290. package/dist/server/http.d.ts +11 -0
  291. package/dist/server/http.js +88 -15
  292. package/dist/server/http.js.map +1 -1
  293. package/dist/server/itc/serverHandlers.js +8 -1
  294. package/dist/server/itc/serverHandlers.js.map +1 -1
  295. package/dist/server/jobs/jobProcess.js +6 -2
  296. package/dist/server/jobs/jobProcess.js.map +1 -1
  297. package/dist/server/jobs/jobs.js +4 -1
  298. package/dist/server/jobs/jobs.js.map +1 -1
  299. package/dist/server/liveSubscriptionAuth.d.ts +26 -4
  300. package/dist/server/liveSubscriptionAuth.js +105 -39
  301. package/dist/server/liveSubscriptionAuth.js.map +1 -1
  302. package/dist/server/loadRootComponents.js +49 -10
  303. package/dist/server/loadRootComponents.js.map +1 -1
  304. package/dist/server/mqtt.d.ts +2 -0
  305. package/dist/server/mqtt.js +165 -30
  306. package/dist/server/mqtt.js.map +1 -1
  307. package/dist/server/nodeName.d.ts +2 -0
  308. package/dist/server/nodeName.js +107 -23
  309. package/dist/server/nodeName.js.map +1 -1
  310. package/dist/server/serverHelpers/Headers.d.ts +25 -0
  311. package/dist/server/serverHelpers/Headers.js +139 -1
  312. package/dist/server/serverHelpers/Headers.js.map +1 -1
  313. package/dist/server/serverHelpers/contentTypes.d.ts +9 -0
  314. package/dist/server/serverHelpers/contentTypes.js +32 -25
  315. package/dist/server/serverHelpers/contentTypes.js.map +1 -1
  316. package/dist/server/serverHelpers/deployValidationState.d.ts +3 -0
  317. package/dist/server/serverHelpers/deployValidationState.js +9 -19
  318. package/dist/server/serverHelpers/deployValidationState.js.map +1 -1
  319. package/dist/server/serverHelpers/operationAuthorizationState.d.ts +12 -0
  320. package/dist/server/serverHelpers/operationAuthorizationState.js +24 -2
  321. package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -1
  322. package/dist/server/serverHelpers/registeredOperations.d.ts +5 -4
  323. package/dist/server/serverHelpers/registeredOperations.js +74 -21
  324. package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
  325. package/dist/server/serverHelpers/requestSanitization.d.ts +11 -0
  326. package/dist/server/serverHelpers/requestSanitization.js +20 -0
  327. package/dist/server/serverHelpers/requestSanitization.js.map +1 -0
  328. package/dist/server/serverHelpers/serverHandlers.js +6 -3
  329. package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
  330. package/dist/server/serverHelpers/serverUtilities.d.ts +18 -0
  331. package/dist/server/serverHelpers/serverUtilities.js +90 -20
  332. package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
  333. package/dist/server/serverHelpers/sharedMessageEncoding.d.ts +67 -0
  334. package/dist/server/serverHelpers/sharedMessageEncoding.js +280 -0
  335. package/dist/server/serverHelpers/sharedMessageEncoding.js.map +1 -0
  336. package/dist/server/serverHelpers/uwsServer.js +19 -1
  337. package/dist/server/serverHelpers/uwsServer.js.map +1 -1
  338. package/dist/server/static.js +24 -28
  339. package/dist/server/static.js.map +1 -1
  340. package/dist/server/storageReclamation.d.ts +12 -0
  341. package/dist/server/storageReclamation.js +26 -0
  342. package/dist/server/storageReclamation.js.map +1 -1
  343. package/dist/server/threads/itc.d.ts +7 -2
  344. package/dist/server/threads/itc.js +5 -1
  345. package/dist/server/threads/itc.js.map +1 -1
  346. package/dist/server/threads/manageThreads.d.ts +26 -3
  347. package/dist/server/threads/manageThreads.js +517 -65
  348. package/dist/server/threads/manageThreads.js.map +1 -1
  349. package/dist/server/threads/socketRouter.js +89 -26
  350. package/dist/server/threads/socketRouter.js.map +1 -1
  351. package/dist/server/threads/threadHeapMemory.d.ts +2 -0
  352. package/dist/server/threads/threadHeapMemory.js +31 -0
  353. package/dist/server/threads/threadHeapMemory.js.map +1 -0
  354. package/dist/server/threads/threadServer.js +46 -15
  355. package/dist/server/threads/threadServer.js.map +1 -1
  356. package/dist/sqlEngine/config.d.ts +1 -3
  357. package/dist/sqlEngine/config.js +19 -16
  358. package/dist/sqlEngine/config.js.map +1 -1
  359. package/dist/sqlTranslator/index.d.ts +1 -1
  360. package/dist/sqlTranslator/index.js +30 -7
  361. package/dist/sqlTranslator/index.js.map +1 -1
  362. package/dist/upgrade/directives/5-3-0.d.ts +7 -0
  363. package/dist/upgrade/directives/5-3-0.js +148 -0
  364. package/dist/upgrade/directives/5-3-0.js.map +1 -0
  365. package/dist/upgrade/directives/directivesController.js +2 -1
  366. package/dist/upgrade/directives/directivesController.js.map +1 -1
  367. package/dist/utility/OperationFunctionCaller.js +2 -1
  368. package/dist/utility/OperationFunctionCaller.js.map +1 -1
  369. package/dist/utility/common_utils.d.ts +16 -0
  370. package/dist/utility/common_utils.js +32 -6
  371. package/dist/utility/common_utils.js.map +1 -1
  372. package/dist/utility/componentNames.d.ts +8 -0
  373. package/dist/utility/componentNames.js +12 -1
  374. package/dist/utility/componentNames.js.map +1 -1
  375. package/dist/utility/environment/environmentManager.js +3 -6
  376. package/dist/utility/environment/environmentManager.js.map +1 -1
  377. package/dist/utility/environment/systemInformation.d.ts +1 -0
  378. package/dist/utility/environment/systemInformation.js +1 -0
  379. package/dist/utility/environment/systemInformation.js.map +1 -1
  380. package/dist/utility/errors/commonErrors.d.ts +2 -0
  381. package/dist/utility/errors/commonErrors.js +2 -0
  382. package/dist/utility/errors/commonErrors.js.map +1 -1
  383. package/dist/utility/errors/hdbError.d.ts +17 -0
  384. package/dist/utility/errors/hdbError.js +30 -1
  385. package/dist/utility/errors/hdbError.js.map +1 -1
  386. package/dist/utility/globalSchema.d.ts +18 -0
  387. package/dist/utility/hdbTerms.d.ts +16 -0
  388. package/dist/utility/hdbTerms.js +18 -2
  389. package/dist/utility/hdbTerms.js.map +1 -1
  390. package/dist/utility/logging/harper_logger.d.ts +2 -0
  391. package/dist/utility/logging/harper_logger.js +91 -14
  392. package/dist/utility/logging/harper_logger.js.map +1 -1
  393. package/dist/utility/logging/logRotator.js +76 -49
  394. package/dist/utility/logging/logRotator.js.map +1 -1
  395. package/dist/utility/nodeIdentity.d.ts +9 -0
  396. package/dist/utility/nodeIdentity.js +58 -0
  397. package/dist/utility/nodeIdentity.js.map +1 -0
  398. package/dist/utility/npmUtilities.js +9 -7
  399. package/dist/utility/npmUtilities.js.map +1 -1
  400. package/dist/utility/operationPermissions.d.ts +3 -1
  401. package/dist/utility/operationPermissions.js +16 -1
  402. package/dist/utility/operationPermissions.js.map +1 -1
  403. package/dist/utility/operation_authorization.d.ts +10 -7
  404. package/dist/utility/operation_authorization.js +212 -41
  405. package/dist/utility/operation_authorization.js.map +1 -1
  406. package/dist/utility/watchPath.d.ts +29 -0
  407. package/dist/utility/watchPath.js +68 -0
  408. package/dist/utility/watchPath.js.map +1 -0
  409. package/dist/utility/watcherFallback.d.ts +86 -0
  410. package/dist/utility/watcherFallback.js +278 -1
  411. package/dist/utility/watcherFallback.js.map +1 -1
  412. package/dist/validation/configValidator.d.ts +12 -0
  413. package/dist/validation/configValidator.js +199 -72
  414. package/dist/validation/configValidator.js.map +1 -1
  415. package/dist/validation/installValidator.js +12 -0
  416. package/dist/validation/installValidator.js.map +1 -1
  417. package/dist/validation/validationWrapper.d.ts +11 -0
  418. package/dist/validation/validationWrapper.js +16 -3
  419. package/dist/validation/validationWrapper.js.map +1 -1
  420. package/index.ts +2 -0
  421. package/json/systemSchema.json +52 -0
  422. package/npm-shrinkwrap.json +196 -194
  423. package/package.json +7 -6
  424. package/resources/DESIGN.md +114 -52
  425. package/resources/DatabaseTransaction.ts +521 -43
  426. package/resources/LMDBTransaction.ts +26 -4
  427. package/resources/PrimaryRocksDatabase.ts +28 -1
  428. package/resources/RecordEncoder.ts +103 -8
  429. package/resources/RequestTarget.ts +2 -0
  430. package/resources/Resource.ts +17 -9
  431. package/resources/ResourceInterface.ts +23 -0
  432. package/resources/RocksIndexStore.ts +30 -9
  433. package/resources/RocksTransactionLogStore.ts +78 -21
  434. package/resources/Table.ts +1110 -159
  435. package/resources/auditStore.ts +331 -73
  436. package/resources/blob.ts +1029 -110
  437. package/resources/branchDatabase.ts +941 -0
  438. package/resources/crdt.ts +76 -12
  439. package/resources/databases.ts +1310 -252
  440. package/resources/defineTable.ts +18 -2
  441. package/resources/graphql.ts +70 -16
  442. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +6 -2
  443. package/resources/longLivedTransactions.ts +360 -0
  444. package/resources/models/backendRegistry.ts +84 -2
  445. package/resources/models/bootstrap.ts +473 -28
  446. package/resources/recordLock.ts +253 -0
  447. package/resources/replayLogs.ts +147 -26
  448. package/resources/replayLogsGuards.ts +171 -8
  449. package/resources/search.ts +154 -7
  450. package/resources/transactionBroadcast.ts +3 -3
  451. package/security/auth.ts +68 -29
  452. package/security/authn/oidc/claims.ts +72 -0
  453. package/security/authn/oidc/identityToken.ts +129 -0
  454. package/security/authn/oidc/jwks.ts +260 -0
  455. package/security/authn/oidc/providers/generic.ts +40 -0
  456. package/security/authn/oidc/providers/githubActions.ts +137 -0
  457. package/security/authn/oidc/providers/index.ts +52 -0
  458. package/security/authn/oidc/tokenExchange.ts +300 -0
  459. package/security/authn/oidc/trustPolicyOperations.ts +343 -0
  460. package/security/authn/oidc/types.ts +41 -0
  461. package/security/certificateVerification/index.ts +54 -13
  462. package/security/certificateVerification/trustedIssuers.ts +76 -0
  463. package/security/certificateVerification/types.ts +1 -0
  464. package/security/credentialProvenance.ts +47 -0
  465. package/security/credentialRejection.ts +22 -0
  466. package/security/deferredAuthentication.ts +71 -0
  467. package/security/impersonation.ts +117 -12
  468. package/security/jsLoader.ts +81 -18
  469. package/security/keys.ts +298 -72
  470. package/security/operationScope.ts +33 -0
  471. package/security/permissionsTranslator.js +23 -0
  472. package/security/tokenAuthentication.ts +233 -12
  473. package/security/user.ts +4 -3
  474. package/server/DESIGN.md +183 -16
  475. package/server/DurableSubscriptionsSession.ts +71 -11
  476. package/server/REST.ts +79 -1
  477. package/server/graphqlQuerying.ts +4 -0
  478. package/server/http.ts +99 -18
  479. package/server/itc/serverHandlers.js +8 -1
  480. package/server/jobs/jobProcess.ts +8 -2
  481. package/server/jobs/jobs.ts +4 -1
  482. package/server/liveSubscriptionAuth.ts +129 -46
  483. package/server/loadRootComponents.js +50 -8
  484. package/server/mqtt.ts +179 -38
  485. package/server/nodeName.ts +103 -21
  486. package/server/serverHelpers/Headers.ts +131 -0
  487. package/server/serverHelpers/contentTypes.ts +29 -21
  488. package/server/serverHelpers/deployValidationState.ts +24 -13
  489. package/server/serverHelpers/operationAuthorizationState.ts +34 -3
  490. package/server/serverHelpers/registeredOperations.ts +79 -22
  491. package/server/serverHelpers/requestSanitization.ts +15 -0
  492. package/server/serverHelpers/serverHandlers.js +6 -3
  493. package/server/serverHelpers/serverUtilities.ts +104 -31
  494. package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
  495. package/server/serverHelpers/uwsServer.ts +17 -2
  496. package/server/static.ts +23 -29
  497. package/server/storageReclamation.ts +23 -0
  498. package/server/threads/itc.js +11 -1
  499. package/server/threads/manageThreads.js +526 -56
  500. package/server/threads/socketRouter.ts +81 -26
  501. package/server/threads/threadHeapMemory.ts +26 -0
  502. package/server/threads/threadServer.js +43 -15
  503. package/sqlTranslator/index.ts +31 -8
  504. package/studio/web/assets/Chat-BnCBegQz.js +2267 -0
  505. package/studio/web/assets/FloatingChat-CoDW1ySS.js +23 -0
  506. package/studio/web/assets/{abnfDiagram-VCTEODGH-C0_BAZyO.js → abnfDiagram-VCTEODGH-B0BebmD2.js} +1 -1
  507. package/studio/web/assets/{alertDialog-DIHt7Z0r.js → alertDialog-CQyAJJhl.js} +1 -1
  508. package/studio/web/assets/{apiToken-c3Rd-w6g.js → apiToken-Bwk5BLXW.js} +1 -1
  509. package/studio/web/assets/applications-DHxGi7JH.js +296 -0
  510. package/studio/web/assets/architecture-7GRP2DOG-LB-MLAAb.js +1 -0
  511. package/studio/web/assets/{architectureDiagram-5GKGNRK7-BWzrASgm.js → architectureDiagram-5GKGNRK7-7SW3GD-K.js} +1 -1
  512. package/studio/web/assets/authStore-C3Nfubqr.js +3 -0
  513. package/studio/web/assets/{blockDiagram-NRAW4CY4-BdJX9Khj.js → blockDiagram-I7D4REHJ-BqguiadH.js} +2 -2
  514. package/studio/web/assets/{button-DhiX-njv.js → button-BIsUKRZq.js} +2 -2
  515. package/studio/web/assets/{c4Diagram-UCG6FXSJ-CI6MzGmQ.js → c4Diagram-7LVT6UL2-LBNf8t_X.js} +1 -1
  516. package/studio/web/assets/channel-yictG-U-.js +1 -0
  517. package/studio/web/assets/{chevron-up-Df2c8uoU.js → chevron-up-DtKGqDn3.js} +1 -1
  518. package/studio/web/assets/{chunk-TEH6E4GO-P87k5mNi.js → chunk-4HAMMTFA-DWtTut21.js} +1 -1
  519. package/studio/web/assets/{chunk-75Z2AOVW-BT8tVmks.js → chunk-75Z2AOVW-QGQD6th2.js} +1 -1
  520. package/studio/web/assets/{chunk-DU6HZSFF-9kAOOmI6.js → chunk-DU6HZSFF-Chq20Ba5.js} +1 -1
  521. package/studio/web/assets/{chunk-F27PBJKO-BW7ao8AY.js → chunk-F27PBJKO-BVA5EPhV.js} +1 -1
  522. package/studio/web/assets/{chunk-GMAD6QVW-BNyXpoQO.js → chunk-GMAD6QVW-BeS7S07A.js} +1 -1
  523. package/studio/web/assets/{chunk-OBVCFTLP-D4wWOqDQ.js → chunk-GVQU2GXP-sbwVIQ8i.js} +1 -1
  524. package/studio/web/assets/{chunk-G27WJ6UU-COyLMcgK.js → chunk-IMKFNOWR-Bnh3tAVd.js} +1 -1
  525. package/studio/web/assets/{chunk-JQ64N6SF-Cyz1IeLf.js → chunk-L3NEJ4N5-COfUyKII.js} +1 -1
  526. package/studio/web/assets/chunk-OSK3NFVY-ByciRftO.js +10 -0
  527. package/studio/web/assets/{chunk-P2QGCYS3-DmIFY4d7.js → chunk-P2QGCYS3-CP1VhG_c.js} +1 -1
  528. package/studio/web/assets/{chunk-POPQ4Y6H-BPrvMyKz.js → chunk-POPQ4Y6H-ClWhhkwW.js} +1 -1
  529. package/studio/web/assets/{chunk-PWAF6VOD-2zB6IW9i.js → chunk-PWAF6VOD-1z1THyS5.js} +1 -1
  530. package/studio/web/assets/{chunk-RHFEMEQ7-2FgyI8YU.js → chunk-SHT3W25Y-LpQkMsah.js} +2 -2
  531. package/studio/web/assets/{chunk-SVP7TREG-FwtbH2QC.js → chunk-SVP7TREG-jtdAHw0S.js} +1 -1
  532. package/studio/web/assets/{chunk-LCL6LL3I-HOzK_ppE.js → chunk-TICWLB2K-VOwzetX-.js} +1 -1
  533. package/studio/web/assets/classDiagram-ZZMXUADV-VaEwSy_g.js +1 -0
  534. package/studio/web/assets/classDiagram-v2-VYDZK3BY-VaEwSy_g.js +1 -0
  535. package/studio/web/assets/{createLucideIcon-BKGPfjm2.js → createLucideIcon-CzW9508A.js} +1 -1
  536. package/studio/web/assets/{cssMode-CEN2mzSA.js → cssMode-s0cWI-_M.js} +1 -1
  537. package/studio/web/assets/{cynefin-OW5HDTMX-BRkpLFQV.js → cynefin-OW5HDTMX-BbdbCvub.js} +1 -1
  538. package/studio/web/assets/{cynefinDiagram-5FMLGOSQ-CHT1DaX6.js → cynefinDiagram-5FMLGOSQ-TP-aIqbt.js} +1 -1
  539. package/studio/web/assets/{dagre-3AP2YEHR-DpUXBh63.js → dagre-GXQ25YYZ-DShnGpGo.js} +1 -1
  540. package/studio/web/assets/{diagram-S7CK7UJ4-BuymVFZT.js → diagram-S7CK7UJ4-aoCVTtcy.js} +1 -1
  541. package/studio/web/assets/{diagram-UQ7AKVKN-CyP148RM.js → diagram-UQ7AKVKN-DglXtQ6x.js} +1 -1
  542. package/studio/web/assets/{diagram-VSXAHHWV-CoCAg3M9.js → diagram-VSXAHHWV-fhEdmkwM.js} +1 -1
  543. package/studio/web/assets/{diagram-VX7I27RA-BpOqCFca.js → diagram-VX7I27RA-DccVJet6.js} +1 -1
  544. package/studio/web/assets/{diagram-Z3DM3KII-Bfpw7Vbj.js → diagram-Z3DM3KII-D-RyJJb7.js} +1 -1
  545. package/studio/web/assets/{dialog-CBf0Mr1d.js → dialog-Cn2uWgD4.js} +1 -1
  546. package/studio/web/assets/{dist-lkA3O3eM.js → dist-DP8UjMB_.js} +1 -1
  547. package/studio/web/assets/{download-BtTOBem-.js → download-B5T5r7ss.js} +1 -1
  548. package/studio/web/assets/{ebnfDiagram-PWID7BFC-DS_6aWqL.js → ebnfDiagram-PWID7BFC-DJGpIpz_.js} +1 -1
  549. package/studio/web/assets/{editor-D8oDeCTL.js → editor-DNcRHK54.js} +1 -1
  550. package/studio/web/assets/{erDiagram-SSCWMZ5O-DJNk6Fgw.js → erDiagram-RLTQ6QDP-CIfNlgkC.js} +1 -1
  551. package/studio/web/assets/eventmodeling-NTZA5JFV-CLxnp2CR.js +1 -0
  552. package/studio/web/assets/flowDiagram-HODETNUW-BIbhmz9f.js +1 -0
  553. package/studio/web/assets/{ganttDiagram-EL5Y4UJY-2pOExxMY.js → ganttDiagram-EL5Y4UJY-BxToTzzD.js} +1 -1
  554. package/studio/web/assets/{getAnalytics-D4LKGeVy.js → getAnalytics-GHK8ORfM.js} +1 -1
  555. package/studio/web/assets/{gitGraph-4MIJSDKK-CH5ZxwzF.js → gitGraph-4MIJSDKK-D2s2w8lE.js} +1 -1
  556. package/studio/web/assets/{gitGraphDiagram-WWUBYQGX-DVIsIhbO.js → gitGraphDiagram-WWUBYQGX-Dwntd4-x.js} +1 -1
  557. package/studio/web/assets/{html-u3vOg7LJ.js → html-Bdssedlg.js} +1 -1
  558. package/studio/web/assets/{htmlMode-DyO31v-P.js → htmlMode-CoDlJ3fw.js} +1 -1
  559. package/studio/web/assets/{index-Cxj2_wsl.css → index-7RMEgVG1.css} +1 -1
  560. package/studio/web/assets/index-D6sxmFLR.js +824 -0
  561. package/studio/web/assets/index.lazy-tmU5BS8s.js +2 -0
  562. package/studio/web/assets/{info-A6RAGUB7-CPQfTnaG.js → info-A6RAGUB7-DYjkvb0C.js} +1 -1
  563. package/studio/web/assets/{infoDiagram-RXCK75RN-DlwLYlwm.js → infoDiagram-27XIBGKW-Bnp1FJE5.js} +1 -1
  564. package/studio/web/assets/{ishikawaDiagram-5VMMS53U-BRXRp29U.js → ishikawaDiagram-5VMMS53U-D9Xh2r6X.js} +1 -1
  565. package/studio/web/assets/{javascript-CUvxOyTC.js → javascript-B8meVSTH.js} +1 -1
  566. package/studio/web/assets/{journeyDiagram-EYS64GPL-B0ou8k0n.js → journeyDiagram-3NMN7TZE-CokIi6ll.js} +2 -2
  567. package/studio/web/assets/{jsonMode-f_IwbF3D.js → jsonMode-DpIPd35T.js} +1 -1
  568. package/studio/web/assets/{kanban-definition-3QL26DDD-uYg7iYzp.js → kanban-definition-UXKFOSKX-CukSFJfX.js} +1 -1
  569. package/studio/web/assets/{languageServices-DXtZ6rEF.js → languageServices-C_5FMJzQ.js} +1 -1
  570. package/studio/web/assets/{lspLanguageFeatures-B4pCF1zO.js → lspLanguageFeatures-BIzNBzPK.js} +1 -1
  571. package/studio/web/assets/{mermaid-parser.core-Ck-fC8b7.js → mermaid-parser.core-BlEsOWNO.js} +3 -3
  572. package/studio/web/assets/{mermaid.core-CP8aNNYm.js → mermaid.core-BlkGaMIH.js} +5 -5
  573. package/studio/web/assets/{mindmap-definition-FBJOCRG2-CgTZ-rit.js → mindmap-definition-YA3MSWOX-IprMc_0j.js} +1 -1
  574. package/studio/web/assets/{notifications-D3tIQ4sg.js → notifications-CQf18QKb.js} +1 -1
  575. package/studio/web/assets/notifications-CvZivSbh.js +1 -0
  576. package/studio/web/assets/{packet-AYTQ26CC-DEyoPtPb.js → packet-AYTQ26CC-Bi3V04Zi.js} +1 -1
  577. package/studio/web/assets/{pegDiagram-XKGWAZYB-DrD-7sD9.js → pegDiagram-XKGWAZYB-BNuPDLZY.js} +1 -1
  578. package/studio/web/assets/{pie-WAS4IAKB-wjj-EI1d.js → pie-WAS4IAKB-_6DoDbng.js} +1 -1
  579. package/studio/web/assets/{pieDiagram-E7YTZNPT-GntqDCzv.js → pieDiagram-E7YTZNPT-DqNb6Ht2.js} +1 -1
  580. package/studio/web/assets/{profile-DZWU7MgT.js → profile-DdOwtntb.js} +1 -1
  581. package/studio/web/assets/{quadrantDiagram-AXDQQJYC-0UeqXQGd.js → quadrantDiagram-AXDQQJYC-BGH9E2YR.js} +1 -1
  582. package/studio/web/assets/{radar-RG4KPBEZ-DFSA5h7k.js → radar-RG4KPBEZ-DDdVczcL.js} +1 -1
  583. package/studio/web/assets/{railroad-74A4TZTK-CaOUG9wR.js → railroad-74A4TZTK-BJUP4Jds.js} +1 -1
  584. package/studio/web/assets/railroad-abnf-HS5TGJTU-Bm3L1L0h.js +1 -0
  585. package/studio/web/assets/railroad-ebnf-LZEXJU2U-CKzLGlkw.js +1 -0
  586. package/studio/web/assets/railroad-peg-WCYAUIDC-S8xLjslx.js +1 -0
  587. package/studio/web/assets/{railroadDiagram-O6MQD6OU-yHUELZaV.js → railroadDiagram-O6MQD6OU-DGTPh2KZ.js} +1 -1
  588. package/studio/web/assets/{regions-CkyurXzE.js → regions-n69fwagr.js} +1 -1
  589. package/studio/web/assets/{register-BUyhWjBO.js → register-PfWTCXWB.js} +3 -3
  590. package/studio/web/assets/{requirementDiagram-EFPCY7ZU-DNEGFjuW.js → requirementDiagram-BXWQKSXE-BJnO6uLz.js} +1 -1
  591. package/studio/web/assets/{sankeyDiagram-P5KCCOFB-DpyAmSVR.js → sankeyDiagram-P5KCCOFB-0vSOdymH.js} +1 -1
  592. package/studio/web/assets/{sequenceDiagram-WJ2MYXX4-TyaT7xNk.js → sequenceDiagram-WJ2MYXX4-hETizDWE.js} +1 -1
  593. package/studio/web/assets/{setComponentFile-CeyKSZAa.js → setComponentFile-Bg6O7X0S.js} +1 -1
  594. package/studio/web/assets/{setup-D2kn7cAA.js → setup-CUx_aUDl.js} +2 -2
  595. package/studio/web/assets/{stateDiagram-HBIQ2CUA-CeEdTArZ.js → stateDiagram-D77RDMKH-CdYQ_KtC.js} +1 -1
  596. package/studio/web/assets/stateDiagram-v2-MP3YSRHH-CdKuzQMT.js +1 -0
  597. package/studio/web/assets/status-D7BVKqX9.js +61 -0
  598. package/studio/web/assets/{swimlanes-XN3QIQJK-B54FmF46.js → swimlanes-42K2YHIH-B8cHIpU4.js} +1 -1
  599. package/studio/web/assets/swimlanesDiagram-VR7AAH4N-DmOSJwaH.js +8 -0
  600. package/studio/web/assets/{tabs-B_G5zscN.js → tabs-BrHu7gJi.js} +1 -1
  601. package/studio/web/assets/{timeline-definition-24CTP7MA-D-a9ujbo.js → timeline-definition-24CTP7MA-BJWYSXqF.js} +1 -1
  602. package/studio/web/assets/{toggleHighContrast-C0UW6rI2.js → toggleHighContrast-DBSyXzMr.js} +1 -1
  603. package/studio/web/assets/{treeView-Q6P3EWNA-CrW_6JnS.js → treeView-Q6P3EWNA-qxe_v6CQ.js} +1 -1
  604. package/studio/web/assets/{treemap-WGGIJYW6-BxyYLdP_.js → treemap-WGGIJYW6-dDo97XXF.js} +1 -1
  605. package/studio/web/assets/{tsMode-DBC0zmDx.js → tsMode-BByKCjBS.js} +1 -1
  606. package/studio/web/assets/{typescript-DApRQir3.js → typescript-DDLnLpw9.js} +1 -1
  607. package/studio/web/assets/{useEntityRestURL-DB6JStU1.js → useEntityRestURL-31CHGaHk.js} +1 -1
  608. package/studio/web/assets/{useLocalStorage-Dtj1QS8_.js → useLocalStorage-BqMR3D8_.js} +1 -1
  609. package/studio/web/assets/vendor-core-c2JRRJpV.js +58 -0
  610. package/studio/web/assets/vendor-datadog-CLUcJXOo.js +6 -0
  611. package/studio/web/assets/{vendor-react-Dyj4O3HE.js → vendor-react-CJV_K1u4.js} +1 -1
  612. package/studio/web/assets/vendor-tanstack-DxzraizX.js +1 -0
  613. package/studio/web/assets/{vendor-ui-vhu-UHhF.js → vendor-ui-BUjK0h8a.js} +2 -2
  614. package/studio/web/assets/{vennDiagram-4TSXK5OY-Cy7s7Mpy.js → vennDiagram-4TSXK5OY-A3i-lCdl.js} +1 -1
  615. package/studio/web/assets/{wardley-WFR3VGLG-BeBL35g2.js → wardley-WFR3VGLG-B0ik-_6g.js} +1 -1
  616. package/studio/web/assets/{wardleyDiagram-VM6X3IG4-BylmIGSg.js → wardleyDiagram-VM6X3IG4-CjrkKWUR.js} +1 -1
  617. package/studio/web/assets/{workers-C0bFIedw.js → workers-pR3jRY9D.js} +1 -1
  618. package/studio/web/assets/x-DIzaLEdK.js +1 -0
  619. package/studio/web/assets/{xml-HWd01lU-.js → xml-2iRnMhQO.js} +1 -1
  620. package/studio/web/assets/{xychartDiagram-S5SC5T6Z-CoKALMXr.js → xychartDiagram-S5SC5T6Z-Biok4GYV.js} +1 -1
  621. package/studio/web/assets/{yaml-CIH0Nt-h.js → yaml-Bf92gJpd.js} +1 -1
  622. package/studio/web/index.html +14 -14
  623. package/upgrade/directives/5-3-0.ts +132 -0
  624. package/upgrade/directives/directivesController.ts +2 -1
  625. package/utility/OperationFunctionCaller.ts +2 -1
  626. package/utility/common_utils.ts +30 -5
  627. package/utility/componentNames.ts +12 -0
  628. package/utility/environment/environmentManager.ts +3 -7
  629. package/utility/environment/systemInformation.ts +7 -0
  630. package/utility/errors/commonErrors.ts +4 -0
  631. package/utility/errors/hdbError.ts +29 -0
  632. package/utility/hdbTerms.ts +17 -0
  633. package/utility/logging/harper_logger.ts +87 -14
  634. package/utility/logging/logRotator.ts +72 -45
  635. package/utility/nodeIdentity.ts +45 -0
  636. package/utility/npmUtilities.ts +10 -8
  637. package/utility/operationPermissions.ts +18 -1
  638. package/utility/operation_authorization.ts +231 -42
  639. package/utility/watchPath.ts +63 -0
  640. package/utility/watcherFallback.ts +270 -0
  641. package/validation/configValidator.ts +209 -72
  642. package/validation/installValidator.ts +15 -0
  643. package/validation/validationWrapper.ts +18 -4
  644. package/studio/web/assets/Chat-JpO8EtUu.js +0 -2067
  645. package/studio/web/assets/FloatingChat-Bcj3xSZu.js +0 -23
  646. package/studio/web/assets/applications-ByqLRKyZ.js +0 -296
  647. package/studio/web/assets/architecture-7GRP2DOG-DNdx5tEU.js +0 -1
  648. package/studio/web/assets/authStore-qKmCZcaf.js +0 -3
  649. package/studio/web/assets/channel-DtCV8PTL.js +0 -1
  650. package/studio/web/assets/chunk-R7TYR2AO-Irip67yr.js +0 -10
  651. package/studio/web/assets/classDiagram-DTDB5LWJ-DbO_dCNE.js +0 -1
  652. package/studio/web/assets/classDiagram-v2-JRS7N3AN-DbO_dCNE.js +0 -1
  653. package/studio/web/assets/eventmodeling-NTZA5JFV-5jbe4A5P.js +0 -1
  654. package/studio/web/assets/flowDiagram-A5DVABFB-Dp9Ezlow.js +0 -1
  655. package/studio/web/assets/index-aSt5tY-L.js +0 -824
  656. package/studio/web/assets/index.lazy-B9jiPwT8.js +0 -2
  657. package/studio/web/assets/notifications-CUoYgU98.js +0 -1
  658. package/studio/web/assets/railroad-abnf-HS5TGJTU-Bc0Qi0WH.js +0 -1
  659. package/studio/web/assets/railroad-ebnf-LZEXJU2U-G8rVVZ2C.js +0 -1
  660. package/studio/web/assets/railroad-peg-WCYAUIDC-CrehKBhC.js +0 -1
  661. package/studio/web/assets/stateDiagram-v2-4QOOHH4V-D4tuw9Su.js +0 -1
  662. package/studio/web/assets/status-D7Xn5ePA.js +0 -61
  663. package/studio/web/assets/swimlanesDiagram-VK2B7HYN-XOhmNEvq.js +0 -8
  664. package/studio/web/assets/vendor-core-RCcadM3e.js +0 -73
  665. package/studio/web/assets/vendor-datadog-BRv-mOv1.js +0 -6
  666. package/studio/web/assets/vendor-tanstack-BiFWSB3W.js +0 -1
  667. package/studio/web/assets/x-B9o9hsep.js +0 -1
  668. /package/studio/web/assets/{sizeCapture-X5ZJPWSS-B0uUizjq.js → sizeCapture-INFHLROL-B0uUizjq.js} +0 -0
@@ -33,23 +33,27 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.RELEASED_TRANSACTION = exports.ImmediateTransaction = exports.DatabaseTransaction = exports.TRANSACTION_STATE = void 0;
36
+ exports.RELEASED_TRANSACTION = exports.ImmediateTransaction = exports.DatabaseTransaction = exports.COMMIT_PHASE_GRACE = exports.TRANSACTION_STATE = void 0;
37
37
  exports.trackOutstandingCommit = trackOutstandingCommit;
38
38
  exports.getOutstandingCommits = getOutstandingCommits;
39
39
  exports.setCommitLatencyRecorder = setCommitLatencyRecorder;
40
40
  exports.getTransactionQueueDepths = getTransactionQueueDepths;
41
41
  exports.replicationConfirmation = replicationConfirmation;
42
42
  exports.transactionOpenTooLongError = transactionOpenTooLongError;
43
+ exports.getAppliedWriteVersion = getAppliedWriteVersion;
43
44
  exports.priorStagedWrite = priorStagedWrite;
44
45
  exports.writeKeyId = writeKeyId;
46
+ exports.shouldSpareCommitPhase = shouldSpareCommitPhase;
45
47
  exports.isReleasedTransaction = isReleasedTransaction;
46
48
  exports.isJoinableScope = isJoinableScope;
47
49
  exports.resetReplayedWritesWarning = resetReplayedWritesWarning;
50
+ exports.setMaxOutstandingTxnDuration = setMaxOutstandingTxnDuration;
48
51
  exports.isWriteSupervised = isWriteSupervised;
49
52
  exports.setTxnExpiration = setTxnExpiration;
50
53
  const blob_ts_1 = require("./blob.js");
51
54
  const commonUtility_ts_1 = require("../utility/lmdb/commonUtility.js");
52
55
  const hdbError_ts_1 = require("../utility/errors/hdbError.js");
56
+ const recordLock_ts_1 = require("./recordLock.js");
53
57
  const harperLogger = __importStar(require("../utility/logging/harper_logger.js"));
54
58
  const envMngr = __importStar(require("../utility/environment/environmentManager.js"));
55
59
  const hdbTerms_ts_1 = require("../utility/hdbTerms.js");
@@ -59,6 +63,7 @@ const promises_1 = require("node:timers/promises");
59
63
  const rocksdb_js_1 = require("@harperfast/rocksdb-js");
60
64
  const RETRY_NOW_VALUE = rocksdb_js_1.constants.RETRY_NOW_VALUE;
61
65
  const ordered_binary_1 = require("ordered-binary");
66
+ const longLivedTransactions_ts_1 = require("./longLivedTransactions.js");
62
67
  const trackedTxns = new Set();
63
68
  // Read options for a rotated generation's native transactions; shared because they never vary.
64
69
  const SNAPSHOT_FREE = Object.freeze({ disableSnapshot: true });
@@ -67,7 +72,7 @@ const SNAPSHOT_FREE = Object.freeze({ disableSnapshot: true });
67
72
  // is what the read-queue-depth metric counts, while this holds one entry per logical transaction — the
68
73
  // chain root — so a chain child can never become its own timeout root (issue #2231).
69
74
  const supervisedWriteRoots = new Set();
70
- const MAX_OUTSTANDING_TXN_DURATION = (0, common_utils_ts_1.convertToMS)(envMngr.get(hdbTerms_ts_1.CONFIG_PARAMS.STORAGE_MAXTRANSACTIONQUEUETIME)) || 45000; // Allow write transactions to be queued for up to 45 seconds before we start rejecting them
75
+ let MAX_OUTSTANDING_TXN_DURATION = (0, common_utils_ts_1.convertToMS)(envMngr.get(hdbTerms_ts_1.CONFIG_PARAMS.STORAGE_MAXTRANSACTIONQUEUETIME)) || 45000; // Allow write transactions to be queued for up to 45 seconds before we start rejecting them
71
76
  const DEBUG_LONG_TXNS = envMngr.get(hdbTerms_ts_1.CONFIG_PARAMS.STORAGE_DEBUGLONGTRANSACTIONS);
72
77
  exports.TRANSACTION_STATE = {
73
78
  CLOSED: 0, // the transaction has been committed or aborted and can no longer be used for writes (if read txn is active, it can be used for reads)
@@ -79,6 +84,12 @@ exports.TRANSACTION_STATE = {
79
84
  LINGERING: 2,
80
85
  };
81
86
  const MAX_RETRIES = 40;
87
+ // Over-limit monitor ticks a transaction parked in its commit phase is spared before it is aborted
88
+ // like any other over-time transaction. Sparing re-arms `timeout`, so each of these costs two
89
+ // monitor intervals — roughly 10 minutes at the 30s default. Generous, so a legitimately large blob
90
+ // write finishes, but bounded, so a pre-commit source that stalls instead of finishing can't pin its
91
+ // read snapshot forever (issue #2062).
92
+ exports.COMMIT_PHASE_GRACE = 10;
82
93
  // Cap the per-retry backoff so replication-applied transactions, which retry conflicts without a
83
94
  // cap (see the commit rejection handler), don't grow the delay unbounded.
84
95
  const MAX_RETRY_DELAY_MS = 1000;
@@ -89,7 +100,27 @@ let outstandingCommitCount = 0;
89
100
  // the whole thread, regardless of how many distinct commits individually cross the threshold — see
90
101
  // the comment at the log site for why a per-commit-only dedup isn't enough under sustained overload.
91
102
  const OVERLOAD_LOG_MIN_INTERVAL_MS = 1000;
92
- let lastOverloadLogAt = -Infinity;
103
+ // One cooldown per reporting site, not one shared: `shed` fires on every bystander write during a
104
+ // wedge and would starve `abandon`, which names a different transaction and is the only server-side
105
+ // record of why a request was failed. Mutates only when it grants, so a caller with its own
106
+ // suppression as well (checkOverloaded's per-node `logged`) must test that first.
107
+ const lastStuckCommitLogAt = { shed: -Infinity, abandon: -Infinity };
108
+ function allowStuckCommitLog(site, now) {
109
+ if (now - lastStuckCommitLogAt[site] <= OVERLOAD_LOG_MIN_INTERVAL_MS)
110
+ return false;
111
+ lastStuckCommitLogAt[site] = now;
112
+ return true;
113
+ }
114
+ // Which database/table, which native transaction, and which request a stuck commit belongs to —
115
+ // without it a wedge gives no indication of what to investigate (harper#2001).
116
+ function describeCommitIdentity(store, startedFrom, nativeTransaction) {
117
+ const nativeTransactionId = nativeTransaction?.id;
118
+ return (`from table: ${store?.rootStore?.databaseName ?? '?'}.${store?.name ?? '?'}` +
119
+ (nativeTransactionId !== undefined ? ` (transaction ${nativeTransactionId})` : '') +
120
+ (startedFrom?.resourceName
121
+ ? `, started from ${startedFrom.resourceName}${startedFrom.method ? '.' + startedFrom.method : ''}`
122
+ : ''));
123
+ }
93
124
  // Track a submitted commit until it settles. Every attempt is tracked unconditionally: a
94
125
  // coordinated retry round and a chained second-store commit are both issued from inside the
95
126
  // preceding commit's own resolve handler, which runs before any reaction that could release a
@@ -167,6 +198,21 @@ function getOutstandingCommits() {
167
198
  // Once per process: committing under open read iterators forces a write replay, so the warning is
168
199
  // about the caller's pattern, not the individual commit.
169
200
  let replayedWritesWarned = false;
201
+ /**
202
+ * Abort a detached native handle. RocksTransaction.abort() throws on one that was already
203
+ * committed or aborted, and every caller is a cleanup path whose own callers have no handler — a
204
+ * throw there would abandon the rest of the cleanup.
205
+ */
206
+ function abortNativeTransaction(transaction, context) {
207
+ if (transaction == null)
208
+ return;
209
+ try {
210
+ transaction.abort();
211
+ }
212
+ catch (error) {
213
+ harperLogger.debug?.(context, error);
214
+ }
215
+ }
170
216
  // The analytics module registers a recorder here at load (dependency inversion, mirroring
171
217
  // `replicationConfirmation` below) so the storage layer doesn't statically import the analytics/server
172
218
  // modules. Unset until analytics loads, and when analytics is disabled the recorder call is cheap.
@@ -251,6 +297,9 @@ function transactionOpenTooLongError() {
251
297
  // 422 signals the request itself must change (split the work), which is the actionable response.
252
298
  return new hdbError_ts_1.ServerError('Transaction was aborted after exceeding the maximum open-transaction time; split long-running work into smaller transactions', 422);
253
299
  }
300
+ function getAppliedWriteVersion(recordVersion, txnLogKey) {
301
+ return recordVersion == null ? txnLogKey : Math.min(recordVersion, txnLogKey);
302
+ }
254
303
  /**
255
304
  * The state a preceding write in this transaction left for `operation`'s key, or undefined if this
256
305
  * is the first write to it. Within a transaction the writes are ordered by program order, and
@@ -300,7 +349,11 @@ class DatabaseTransaction {
300
349
  readTxnRefCount;
301
350
  readTxnsUsed;
302
351
  timeout;
352
+ writeTick = -1;
303
353
  timeoutBudget = 0;
354
+ // Initialized rather than `declare`d so the class shape stays monomorphic on the write path. One clock
355
+ // read per handle is what lets the monitor age a handle without calling into the registry every tick.
356
+ handleOpenedAt = 0;
304
357
  // save() only stages here; ImmediateTransaction overrides it to commit, which addWrite must not defer
305
358
  saveCommits = false;
306
359
  // True where save() puts the write into this transaction's native handle, which is what lets a scope
@@ -319,6 +372,22 @@ class DatabaseTransaction {
319
372
  // asks to stop reading a pinned snapshot, so re-pinning one for the rest of the scope would take
320
373
  // back what it asked for.
321
374
  snapshotFree = false;
375
+ // Set while commit() is parked in its pre-commit await (`before`/`beforeIntermediate` completions —
376
+ // in practice a blob's durable file write). The write set is sealed and the caller is awaiting the
377
+ // commit, so this is core's own I/O rather than an application holding a transaction open, which is
378
+ // what the open-transaction limit polices: the monitor spares it for COMMIT_PHASE_GRACE ticks
379
+ // instead of poisoning it (issue #2062).
380
+ committing = false;
381
+ commitPhaseTicks = 0;
382
+ setCommitPhase(committing) {
383
+ // A commit phase covers the sealed write set across the whole multi-store chain.
384
+ for (let txn = this; txn; txn = txn.next) {
385
+ txn.committing = committing;
386
+ txn.commitChainHead = committing ? this : undefined;
387
+ if (committing)
388
+ txn.commitPhaseTicks = 0;
389
+ }
390
+ }
322
391
  getReadTxn(disableSnapshot) {
323
392
  this.readTxnRefCount = (this.readTxnRefCount || 0) + 1;
324
393
  // The limit is an IDLE limit. Writes always re-arm it (see addWrite), but reads only do so
@@ -367,6 +436,7 @@ class DatabaseTransaction {
367
436
  this.transaction = transaction;
368
437
  this.readTxnsUsed = 1;
369
438
  this.baseReadRefConsumed = false;
439
+ this.handleOpenedAt = performance.now();
370
440
  }
371
441
  /**
372
442
  * Drop this link's supervision claim, and the root's with it once no link in the chain still holds
@@ -407,6 +477,7 @@ class DatabaseTransaction {
407
477
  this.transaction = null;
408
478
  this.readTxnsUsed = 0;
409
479
  this.readTxnRefCount = 0;
480
+ this.handleOpenedAt = 0;
410
481
  return transaction;
411
482
  }
412
483
  useReadTxn(disableSnapshot) {
@@ -453,12 +524,7 @@ class DatabaseTransaction {
453
524
  */
454
525
  releaseReadTxn() {
455
526
  const transaction = this.detachOwnedTransaction();
456
- try {
457
- transaction?.abort();
458
- }
459
- catch (error) {
460
- harperLogger.debug?.('releasing timed-out read transaction', error);
461
- }
527
+ abortNativeTransaction(transaction, 'releasing timed-out read transaction');
462
528
  this.completeDeferredContextRelease();
463
529
  }
464
530
  /**
@@ -538,6 +604,77 @@ class DatabaseTransaction {
538
604
  }
539
605
  }
540
606
  }
607
+ registerRecordLock(handle) {
608
+ if (!this.recordLocks)
609
+ this.recordLocks = new Map();
610
+ let storeMap = this.recordLocks.get(handle.store);
611
+ if (!storeMap)
612
+ this.recordLocks.set(handle.store, (storeMap = new Map()));
613
+ storeMap.set(handle.keyId, handle);
614
+ }
615
+ recordLockFor(store, keyId) {
616
+ const storeMap = this.recordLocks?.get(store);
617
+ if (!storeMap)
618
+ return undefined;
619
+ const h = storeMap.get(keyId);
620
+ if (!h)
621
+ return undefined;
622
+ if (!h.released)
623
+ return h;
624
+ // Prune released handles so they don't accumulate; an expired handle checking re-entrancy
625
+ // would otherwise be seen as the holder and incorrectly granted access.
626
+ storeMap.delete(keyId);
627
+ return undefined;
628
+ }
629
+ unregisterRecordLock(handle) {
630
+ const storeMap = this.recordLocks?.get(handle.store);
631
+ if (storeMap?.get(handle.keyId) === handle)
632
+ storeMap.delete(handle.keyId);
633
+ }
634
+ registerPendingLock(store, keyId, pending) {
635
+ if (!this.pendingLocks)
636
+ this.pendingLocks = new Map();
637
+ let storeMap = this.pendingLocks.get(store);
638
+ if (!storeMap)
639
+ this.pendingLocks.set(store, (storeMap = new Map()));
640
+ storeMap.set(keyId, pending);
641
+ }
642
+ pendingLockFor(store, keyId) {
643
+ return this.pendingLocks?.get(store)?.get(keyId);
644
+ }
645
+ unregisterPendingLock(store, keyId) {
646
+ this.pendingLocks?.get(store)?.delete(keyId);
647
+ }
648
+ /** Release every transaction-scoped lock() handle this link owns. */
649
+ releaseRecordLocks() {
650
+ const recordLocks = this.recordLocks;
651
+ if (!recordLocks)
652
+ return;
653
+ for (const [store, storeMap] of recordLocks) {
654
+ for (const [keyId, handle] of storeMap) {
655
+ if (handle.hold)
656
+ continue; // hold handles outlive the transaction; released by unlock()
657
+ handle.release();
658
+ storeMap.delete(keyId);
659
+ }
660
+ if (storeMap.size === 0)
661
+ recordLocks.delete(store);
662
+ }
663
+ if (recordLocks.size === 0)
664
+ this.recordLocks = undefined;
665
+ }
666
+ noteCommittedLockVersions() {
667
+ const recordLocks = this.recordLocks;
668
+ if (!recordLocks)
669
+ return;
670
+ for (const write of this.writes) {
671
+ if (write?.appliedRecordVersion == null)
672
+ continue;
673
+ const handle = write.lockHandle ?? recordLocks.get(write.store)?.get(writeKeyId(write.key));
674
+ if (handle && !handle.released)
675
+ handle.noteHolderVersion(write.appliedRecordVersion);
676
+ }
677
+ }
541
678
  /**
542
679
  * Discard the staged write set (committed or aborted); the per-key chain must go with it so a
543
680
  * reused transaction never bases a write on a previous batch's staged state.
@@ -597,25 +734,20 @@ class DatabaseTransaction {
597
734
  // original per-request log was fixed to avoid, just shifted from per-request to per-commit.
598
735
  // A commit skipped by the cooldown is NOT marked `logged`, so it still gets a log later if
599
736
  // it's still the oldest once the cooldown clears, rather than going silent forever.
600
- if (!oldestOutstandingCommit.logged && now - lastOverloadLogAt > OVERLOAD_LOG_MIN_INTERVAL_MS) {
737
+ if (!oldestOutstandingCommit.logged && allowStuckCommitLog('shed', now)) {
601
738
  // Log once per stuck commit (not once per rejected request, harper#2001): a wedged
602
739
  // thread otherwise logs nothing at all server-side while rejecting every write with a
603
740
  // 503, which was the single biggest obstacle to root-causing a recurrence. The flag lives
604
741
  // on the node itself, so if THIS commit settles while still over the limit and a
605
742
  // different one is now oldest, that one logs too instead of staying silent forever.
606
743
  oldestOutstandingCommit.logged = true;
607
- lastOverloadLogAt = now;
608
- const nativeTransactionId = oldestOutstandingCommit.nativeTransaction?.id;
609
- const store = oldestOutstandingCommit.store;
610
- const startedFrom = oldestOutstandingCommit.startedFrom;
611
744
  harperLogger.error(`Rejecting writes on this thread: a commit has been outstanding for ` +
612
745
  `${Math.round(now - oldestOutstandingCommit.start)}ms (exceeds the ` +
613
- `${MAX_OUTSTANDING_TXN_DURATION}ms limit), from table: ${store?.rootStore?.databaseName ?? '?'}.${store?.name ?? '?'}` +
614
- (nativeTransactionId !== undefined ? ` (transaction ${nativeTransactionId})` : '') +
615
- (startedFrom?.resourceName
616
- ? `, started from ${startedFrom.resourceName}${startedFrom.method ? '.' + startedFrom.method : ''}`
617
- : '') +
618
- `. Further record updates and publishes from new application requests on this thread ` +
746
+ `${MAX_OUTSTANDING_TXN_DURATION}ms limit), ` +
747
+ describeCommitIdentity(oldestOutstandingCommit.store, oldestOutstandingCommit.startedFrom, oldestOutstandingCommit.nativeTransaction) +
748
+ `.` +
749
+ (0, longLivedTransactions_ts_1.describeHolderCandidates)(oldestOutstandingCommit.store?.rootStore?.path, oldestOutstandingCommit.nativeTransaction?.id) +
750
+ ` Further record updates and publishes from new application requests on this thread ` +
619
751
  `will be rejected with 503 until the commit settles or the process is restarted (deletes, ` +
620
752
  `and writes applied from a canonical source, e.g. replication or a caching source, bypass this check).`);
621
753
  }
@@ -676,6 +808,7 @@ class DatabaseTransaction {
676
808
  // Independent write-recency signal for chainStillActive (see the field comment) — reads never
677
809
  // touch this, only writes do.
678
810
  this.writeTimeout = this.timeout;
811
+ this.writeTick = monitorTick;
679
812
  this.linkWrite(operation);
680
813
  this.writes.push(operation);
681
814
  operation.stagedIn = this;
@@ -705,7 +838,34 @@ class DatabaseTransaction {
705
838
  return operation;
706
839
  }
707
840
  save(operation, transaction, reloadEntry = false, options) {
708
- let txnTime = this.timestamp;
841
+ const lockHandle = operation.lockHandle;
842
+ // Guard: a write staged through an expired or released lock handle must not land.
843
+ // The handle's lease timer already unlocked the native key; another holder may have taken it.
844
+ if (lockHandle && (lockHandle.expired || lockHandle.released)) {
845
+ // Remove the operation from the staged set so subsequent writes on this context do not
846
+ // re-throw 409 due to a stale null-saved entry sitting in this.writes.
847
+ const failedIdx = this.writes.indexOf(operation);
848
+ if (failedIdx > -1)
849
+ this.writes[failedIdx] = null;
850
+ throw (0, recordLock_ts_1.lockNotHeldError)(lockHandle);
851
+ }
852
+ // Lock-write timestamp rules.
853
+ if (lockHandle) {
854
+ if (this.open === exports.TRANSACTION_STATE.CLOSED || this.saveCommits) {
855
+ // CLOSED path (second+ write per ImmediateTransaction cycle) OR the first write in
856
+ // an ImmediateTransaction (open=OPEN until commit sets it CLOSED, but saveCommits
857
+ // signals the per-write-commit semantics): stamp with nextHolderVersion() so that
858
+ // each sequential save() gets its own monotonically increasing stamp — scoped or hold.
859
+ // The stamp stays on the operation and is consumed below rather than assigned to
860
+ // this.timestamp: pinning the link's clock would stamp every OTHER write staged on
861
+ // the same context before the commit resets it — a concurrent write in the caller's
862
+ // own Promise.all, or the next operation in a retry/replay save loop — with the
863
+ // lock's version, which LWW then silently drops against a newer record version.
864
+ if (!operation.lockStamp)
865
+ operation.lockStamp = lockHandle.holderVersionCandidate();
866
+ }
867
+ }
868
+ let txnTime = operation.lockStamp ?? this.timestamp;
709
869
  // Only an OPEN transaction accepts new staged writes. After commit, this.transaction may still
710
870
  // be retained for outstanding read iterators; staging into it would silently discard the write
711
871
  // when doneReadTxn() aborts the handle, so such writes commit immediately on a fresh
@@ -750,13 +910,18 @@ class DatabaseTransaction {
750
910
  }
751
911
  if (!txnTime)
752
912
  txnTime = this.timestamp = transaction.getTimestamp();
913
+ // `txnTime` is this transaction's timestamp — the key its entries take in the per-origin log.
914
+ // A write applied from elsewhere carries the origin's record version too, and that is what the
915
+ // record is stored at; the two coincide for every locally-originated write. Gated on the apply
916
+ // flags so an ordinary write never reads the property (harper#2412).
917
+ const writeVersion = this.sourceApply || this.isReplay ? getAppliedWriteVersion(operation.recordVersion, txnTime) : txnTime;
753
918
  if (reloadEntry || operation.entry === undefined) {
754
919
  operation.entry = operation.store.getEntry(operation.key, { transaction });
755
920
  }
756
921
  if (!operation.saved) {
757
922
  operation.saved = true;
758
923
  // immediately execute in this transaction
759
- if (operation.validate?.(txnTime, this) === false) {
924
+ if (operation.validate?.(writeVersion, this) === false) {
760
925
  operation.commit = () => { }; // noop if we try again
761
926
  return;
762
927
  }
@@ -767,7 +932,13 @@ class DatabaseTransaction {
767
932
  if (result?.then)
768
933
  this.stageCompletion(result);
769
934
  }
770
- const completion = operation.commit(txnTime, operation.entry, this.retries > 0, transaction);
935
+ if (lockHandle || this.recordLocks)
936
+ operation.trackRecordVersion = true;
937
+ if (operation.trackRecordVersion)
938
+ operation.recordVersionApplied = false;
939
+ const completion = operation.commit(writeVersion, operation.entry, this.retries > 0, transaction);
940
+ if (operation.trackRecordVersion)
941
+ operation.appliedRecordVersion = operation.recordVersionApplied ? writeVersion : undefined;
771
942
  if (typeof completion?.then === 'function')
772
943
  this.stageCompletion(completion);
773
944
  // Sticky record that THIS write staged with its audit entry appended (log entries batch on the
@@ -780,7 +951,13 @@ class DatabaseTransaction {
780
951
  operation.appendedAuditEntry = true;
781
952
  }
782
953
  if (immediateCommit) {
783
- return this.commit({ ...options, transaction }); // immediately commit if the harper transaction is closed
954
+ // immediately commit if the harper transaction is closed
955
+ const innerCommit = this.commit({ ...options, transaction });
956
+ // Expose on the operation so the lock-writable Table.save() path can await the real
957
+ // native commit — without this the ImmediateTransaction outer commit resolves before
958
+ // the native transaction.commit() settles (fire-and-forget from the if-branch).
959
+ operation.innerCommit = innerCommit;
960
+ return innerCommit;
784
961
  }
785
962
  }
786
963
  /**
@@ -792,17 +969,38 @@ class DatabaseTransaction {
792
969
  // reused across retries — the native layer resets it in place (fresh snapshot) on IsBusy/TryAgain —
793
970
  // but reassigned to a fresh replay transaction when outstanding read iterators retain this.transaction
794
971
  let transaction = options.transaction ?? this.transaction;
795
- for (let i = 0; i < this.writes.length; i++) {
796
- let operation = this.writes[i];
797
- if (!operation || (this.retries === 0 && operation.saved))
798
- continue;
799
- this.save(operation, transaction, i < this.validated, options);
972
+ try {
973
+ for (let i = 0; i < this.writes.length; i++) {
974
+ let operation = this.writes[i];
975
+ if (!operation || (this.retries === 0 && operation.saved))
976
+ continue;
977
+ this.save(operation, transaction, i < this.validated, options);
978
+ }
979
+ }
980
+ catch (error) {
981
+ this.abort();
982
+ throw error;
800
983
  }
801
984
  this.validated = this.writes.length;
802
985
  const completions = this.completions;
803
986
  if (completions.length > 0)
804
987
  this.completions = []; // reset
988
+ const stagedWrites = this.writes.length;
989
+ if (completions.length > 0) {
990
+ this.setCommitPhase(true);
991
+ }
805
992
  return (0, when_ts_1.when)(completions.length > 0 ? Promise.all(completions) : null, () => {
993
+ if (completions.length > 0)
994
+ this.setCommitPhase(false);
995
+ // The transaction can be aborted underneath us while we are parked in the await above — by the
996
+ // monitor once the commit phase outlives its grace, or through the multi-store poison chain.
997
+ // abort() cleared the write set and released the handle, so resuming would commit nothing and
998
+ // resolve as SUCCESS: the caller is told its write landed when it was dropped, and a write
999
+ // carrying a blob is left holding an instance whose file was unlinked (issue #2062).
1000
+ if (this.timedOut)
1001
+ throw transactionOpenTooLongError();
1002
+ if (stagedWrites > 0 && this.writes.length === 0 && this.open === exports.TRANSACTION_STATE.CLOSED)
1003
+ throw new hdbError_ts_1.ServerError('Transaction was aborted while its commit was waiting on pre-commit work', 500);
806
1004
  if (this.writes.length > this.validated) {
807
1005
  // check just in case we got any more transactions while we were waiting, if so just recursively continue to finish the additional writes now
808
1006
  return this.commit(options);
@@ -936,14 +1134,22 @@ class DatabaseTransaction {
936
1134
  // claimed this per-database transaction in txnForContext and so can name the wrong
937
1135
  // table when a transaction spans more than one table in the same database.
938
1136
  trackOutstandingCommit(commitResolution, this.writes[0]?.store, this.startedFrom, transaction);
1137
+ // Every retry round and every chained store re-enters here and must inherit the chain
1138
+ // root's clock rather than restart it, so only the first submission stamps.
1139
+ const chainRoot = this.root ?? this;
1140
+ if (chainRoot.commitStartedAt == null)
1141
+ chainRoot.commitStartedAt = performance.now();
939
1142
  const completions = [];
940
- return commitResolution.then((commitResult) => {
1143
+ const commitOutcome = commitResolution.then((commitResult) => {
941
1144
  if (commitResult === RETRY_NOW_VALUE) {
942
1145
  this.retries++;
943
1146
  harperLogger.debug?.('coordinated retry', transaction.id, this.retries);
944
1147
  // Mark this specific native transaction as a retry so RocksTransactionLogStore
945
1148
  // skips re-writing its already-staged txn-log entries (#2).
946
1149
  transaction.isRetry = true;
1150
+ const pastBudget = this.elapsedPastCommitBudget();
1151
+ if (pastBudget)
1152
+ this.abandonCommitAfterDeadline(transaction, pastBudget);
947
1153
  // Mirror the ERR_BUSY cap/warn policy: non-sourceApply transactions abort
948
1154
  // at MAX_RETRIES; sourceApply transactions keep retrying with periodic warn.
949
1155
  if (this.retries > MAX_RETRIES) {
@@ -996,9 +1202,12 @@ class DatabaseTransaction {
996
1202
  if (write?.savedBlobs && (write.skipped || (write.superseded && !write.blobsAuditReferenced)))
997
1203
  (0, blob_ts_1.cleanupUnusedBlobs)(write.savedBlobs, (0, blob_ts_1.collectRetainedFileIds)(write.store.getEntry(write.key)?.value));
998
1204
  }
1205
+ if (this.recordLocks)
1206
+ this.noteCommittedLockVersions();
999
1207
  // now reset transactions tracking; this transaction be reused and committed again
1000
1208
  this.retries = 0; // reset per-native-transaction retry counter so a reused DatabaseTransaction's next batch starts fresh
1001
1209
  this.clearWrites();
1210
+ this.releaseRecordLocks();
1002
1211
  if (options.doneWriting)
1003
1212
  this.endScopeOwnership();
1004
1213
  this.releaseContext(!!options.doneWriting);
@@ -1050,6 +1259,11 @@ class DatabaseTransaction {
1050
1259
  // premature publish, and no fresh-transaction replay that would drop the entry.
1051
1260
  // Mark the native transaction as a retry so RocksTransactionLogStore skips re-staging entries.
1052
1261
  transaction.isRetry = true;
1262
+ // Before the backoff gate below: the budget can already be spent on the first
1263
+ // retry when an earlier store in this chain consumed it.
1264
+ const pastBudget = this.elapsedPastCommitBudget();
1265
+ if (pastBudget)
1266
+ this.abandonCommitAfterDeadline(transaction, pastBudget);
1053
1267
  if (this.retries > 2) {
1054
1268
  // Transactions applying data from a canonical source of truth (replication peer or
1055
1269
  // external caching source) must never drop a write on a transient conflict: there is no
@@ -1094,24 +1308,43 @@ class DatabaseTransaction {
1094
1308
  // finished and its durability is unknown, so ownership goes with it.
1095
1309
  this.endScopeOwnership();
1096
1310
  this.releaseContext(!!options.doneWriting);
1311
+ this.releaseRecordLocks();
1312
+ this.timestamp = 0;
1097
1313
  throw error;
1098
1314
  }
1099
1315
  });
1316
+ // `commitOutcome` settles when the LOGICAL commit ends — its success branch awaits the
1317
+ // chained stores' own commits — so releasing here covers every terminal exit (success,
1318
+ // retry exhaustion, abandonment, terminal failure) in one place rather than five.
1319
+ // Released through the RETURNED promise rather than a second subscriber on
1320
+ // `commitOutcome`: a subscriber would mark a dropped commit rejection as handled and
1321
+ // silence the unhandled-rejection that surfaces it.
1322
+ return commitOutcome.then((resolution) => {
1323
+ chainRoot.commitStartedAt = undefined;
1324
+ return resolution;
1325
+ }, (error) => {
1326
+ chainRoot.commitStartedAt = undefined;
1327
+ throw error;
1328
+ });
1100
1329
  }
1101
1330
  for (const write of this.writes) {
1102
1331
  if (write?.savedBlobs && (write.skipped || (write.superseded && !write.blobsAuditReferenced)))
1103
1332
  (0, blob_ts_1.cleanupUnusedBlobs)(write.savedBlobs, (0, blob_ts_1.collectRetainedFileIds)(write.store.getEntry(write.key)?.value));
1104
1333
  }
1334
+ if (this.recordLocks)
1335
+ this.noteCommittedLockVersions();
1105
1336
  this.clearWrites();
1337
+ this.releaseRecordLocks();
1106
1338
  if (options.doneWriting)
1107
1339
  this.endScopeOwnership();
1108
1340
  this.releaseContext(!!options.doneWriting);
1109
1341
  const txnResolution = {
1110
1342
  txnTime: this.timestamp,
1111
1343
  };
1344
+ this.timestamp = 0; // reset like the async path (~1279) so stale lock stamps don't persist
1112
1345
  if (this.next) {
1113
1346
  // now run any other transactions
1114
- options.timestamp = this.timestamp;
1347
+ options.timestamp = txnResolution.txnTime;
1115
1348
  // as above: the next store must not inherit this store's explicit native transaction
1116
1349
  let nextResolution;
1117
1350
  try {
@@ -1130,7 +1363,7 @@ class DatabaseTransaction {
1130
1363
  // scope resumable after a partially failed mid-scope commit.
1131
1364
  this.completeMidScopeCommit(options);
1132
1365
  return {
1133
- txnTime: this.timestamp,
1366
+ txnTime: txnResolution.txnTime,
1134
1367
  next: nextResolution,
1135
1368
  };
1136
1369
  }, (error) => {
@@ -1146,6 +1379,7 @@ class DatabaseTransaction {
1146
1379
  this.completeMidScopeCommit(options);
1147
1380
  return txnResolution;
1148
1381
  }, (error) => {
1382
+ this.setCommitPhase(false);
1149
1383
  this.abort();
1150
1384
  throw error;
1151
1385
  });
@@ -1193,6 +1427,7 @@ class DatabaseTransaction {
1193
1427
  if (this.transaction)
1194
1428
  this.releaseReadTxn();
1195
1429
  this.open = exports.TRANSACTION_STATE.CLOSED;
1430
+ this.timestamp = 0; // a lock stamp pinned for this write set must not leak into the next
1196
1431
  this.drainCompletions();
1197
1432
  try {
1198
1433
  for (const write of this.writes) {
@@ -1203,6 +1438,7 @@ class DatabaseTransaction {
1203
1438
  finally {
1204
1439
  this.endScopeOwnership(); // the scope is over; nothing may rotate this instance again
1205
1440
  this.clearWrites();
1441
+ this.releaseRecordLocks();
1206
1442
  // A timeout-poisoned abort (abortDueToTimeout()) is the one abort that is NOT "reuse-free":
1207
1443
  // Resource.ts's dispatcher deliberately keeps joining a `timedOut` transaction (instead of
1208
1444
  // starting a fresh one) so the rest of the logical operation fails atomically via the
@@ -1222,6 +1458,56 @@ class DatabaseTransaction {
1222
1458
  }
1223
1459
  }
1224
1460
  }
1461
+ /** How long this logical commit may keep retrying: the thread-wide queue limit, or its own larger explicit budget. */
1462
+ commitConflictBudget() {
1463
+ return Math.max(MAX_OUTSTANDING_TXN_DURATION, (this.root ?? this).timeoutBudget || 0);
1464
+ }
1465
+ /**
1466
+ * How long this logical commit has been retrying once it is past its budget, else 0. rocksdb-js
1467
+ * returns control from a parked commit every `ROCKSDB_JS_PARK_TIMEOUT_MS` even when the intent
1468
+ * holder never releases, so without this bound a request-path commit retries the attempt cap out
1469
+ * — minutes past the queue limit an operator configured (issue #2450).
1470
+ *
1471
+ * Source-applied writes are exempt for the same reason they are exempt from the attempt cap:
1472
+ * there is no resubscribe/sequence-resume path, so dropping one permanently diverges this node.
1473
+ */
1474
+ elapsedPastCommitBudget() {
1475
+ if (this.sourceApply)
1476
+ return 0;
1477
+ const startedAt = (this.root ?? this).commitStartedAt;
1478
+ if (startedAt == null)
1479
+ return 0;
1480
+ const elapsed = performance.now() - startedAt;
1481
+ return elapsed > this.commitConflictBudget() ? elapsed : 0;
1482
+ }
1483
+ /**
1484
+ * Abandon a logical commit that stayed in write-intent conflict past its budget. Cleanup is
1485
+ * retry exhaustion's, so no link leaks a native handle or read snapshot; the error is distinct
1486
+ * because the condition is distinct — every attempt reported transient contention, so a later
1487
+ * request can succeed once the holder releases, which the generic exhaustion 500 does not say.
1488
+ *
1489
+ * Only a chain root may report `retryable`: a link commits solely from its predecessor's success
1490
+ * handler, so anywhere else in the chain an earlier store has already landed durable audit
1491
+ * entries and hooks that a replayed request would run twice. A head whose scope already rotated
1492
+ * through a mid-scope commit is in the same position.
1493
+ */
1494
+ abandonCommitAfterDeadline(headTransaction, elapsedMs) {
1495
+ const elapsed = Math.round(elapsedMs);
1496
+ const budget = this.commitConflictBudget();
1497
+ const retryable = !this.root && !this.snapshotFree;
1498
+ if (allowStuckCommitLog('abandon', performance.now())) {
1499
+ harperLogger.error(`Abandoning a write transaction: its commit has been in write-intent conflict for ${elapsed}ms ` +
1500
+ `(exceeds the ${budget}ms limit) across ${this.retries} retries, ` +
1501
+ describeCommitIdentity(this.writes[0]?.store, this.startedFrom, headTransaction) +
1502
+ `.` +
1503
+ (0, longLivedTransactions_ts_1.describeHolderCandidates)(this.writes[0]?.store?.rootStore?.path, headTransaction?.id) +
1504
+ ` Another transaction holds a conflicting write intent and has not completed; the request is ` +
1505
+ `failed with a 503${retryable ? '' : ' (not retryable — an earlier store in this transaction already committed)'} ` +
1506
+ `rather than waiting further.`);
1507
+ }
1508
+ this.abortChainAfterRetries(headTransaction);
1509
+ throw new hdbError_ts_1.TransactionCommitConflictTimeoutError(`Commit was in conflict with ongoing writes for ${elapsed}ms, exceeding the ${budget}ms limit; transaction abandoned after ${this.retries} retries`, retryable);
1510
+ }
1225
1511
  /**
1226
1512
  * Give up on a chain of linked transactions after exhausting conflict retries: poison every link
1227
1513
  * first, then abort each link's native transaction and release its DatabaseTransaction-level
@@ -1317,12 +1603,7 @@ class DatabaseTransaction {
1317
1603
  // throws. abort() rather than the native abort alone: it reclaims blobs a replayed write
1318
1604
  // staged.
1319
1605
  this.detachOwnedTransaction();
1320
- try {
1321
- transaction?.abort();
1322
- }
1323
- catch (abortError) {
1324
- harperLogger.debug?.('aborting a transaction whose synchronous commit failed', abortError);
1325
- }
1606
+ abortNativeTransaction(transaction, 'aborting a transaction whose synchronous commit failed');
1326
1607
  try {
1327
1608
  this.abort();
1328
1609
  }
@@ -1341,6 +1622,18 @@ class DatabaseTransaction {
1341
1622
  }
1342
1623
  }
1343
1624
  exports.DatabaseTransaction = DatabaseTransaction;
1625
+ function shouldSpareCommitPhase(txn, checkedCommitPhaseChains) {
1626
+ if (!txn.committing)
1627
+ return false;
1628
+ if (txn.sourceApply || txn.isReplay)
1629
+ return true;
1630
+ const commitChainHead = txn.commitChainHead ?? txn;
1631
+ if (!checkedCommitPhaseChains.has(commitChainHead)) {
1632
+ checkedCommitPhaseChains.add(commitChainHead);
1633
+ commitChainHead.commitPhaseTicks++;
1634
+ }
1635
+ return commitChainHead.commitPhaseTicks <= exports.COMMIT_PHASE_GRACE;
1636
+ }
1344
1637
  class ImmediateTransaction extends DatabaseTransaction {
1345
1638
  isCommitting = false;
1346
1639
  saveCommits = true;
@@ -1349,18 +1642,50 @@ class ImmediateTransaction extends DatabaseTransaction {
1349
1642
  this.db = db;
1350
1643
  }
1351
1644
  save(...args) {
1352
- const transaction = args[0];
1645
+ const operation = args[0]; // the staged write, not a transaction — commit() re-enters here with it
1353
1646
  if (this.isCommitting) {
1354
1647
  // if we are in the commit, do the save and force a reload so we get a read within the transaction
1355
- super.save(transaction, null, true);
1648
+ super.save(operation, null, true);
1356
1649
  }
1357
1650
  else {
1358
1651
  this.isCommitting = true;
1359
- return (0, when_ts_1.when)(this.commit(), () => {
1652
+ // A synchronous throw from commit() (e.g. a 409 from an expired lock handle) would
1653
+ // otherwise leave isCommitting latched at true, causing every subsequent save() in this
1654
+ // context to take the fire-and-forget if-branch and silently drop writes.
1655
+ let commitResult;
1656
+ try {
1657
+ commitResult = this.commit();
1658
+ }
1659
+ catch (err) {
1660
+ this.isCommitting = false;
1661
+ throw err;
1662
+ }
1663
+ return (0, when_ts_1.when)(commitResult, () => {
1664
+ this.isCommitting = false;
1665
+ }, (err) => {
1666
+ // Async rejection (e.g. a rejected rocksdb commit promise) must also clear the
1667
+ // latch; without this, every subsequent save() silently fire-and-forgets.
1360
1668
  this.isCommitting = false;
1669
+ throw err;
1361
1670
  });
1362
1671
  }
1363
1672
  }
1673
+ // Without an explicit transaction() a live lock is released only by unlock() or its lease, never
1674
+ // by the per-write commit. Expired handles are pruned so a reused context does not retain every key.
1675
+ releaseRecordLocks() {
1676
+ const recordLocks = this.recordLocks;
1677
+ if (!recordLocks)
1678
+ return;
1679
+ for (const [store, storeMap] of recordLocks) {
1680
+ for (const [keyId, handle] of storeMap)
1681
+ if (handle.released)
1682
+ storeMap.delete(keyId);
1683
+ if (storeMap.size === 0)
1684
+ recordLocks.delete(store);
1685
+ }
1686
+ if (recordLocks.size === 0)
1687
+ this.recordLocks = undefined;
1688
+ }
1364
1689
  // @ts-expect-error accessor overriding property
1365
1690
  get timestamp() {
1366
1691
  return this._timestamp || (this._timestamp = (0, commonUtility_ts_1.getNextMonotonicTime)());
@@ -1433,6 +1758,7 @@ function isJoinableScope(transaction) {
1433
1758
  return transaction?.open === exports.TRANSACTION_STATE.OPEN && !transaction.saveCommits;
1434
1759
  }
1435
1760
  let timer;
1761
+ let monitorTick = 0;
1436
1762
  /**
1437
1763
  * True when a link other than `txn` in the same multi-store chain was written recently enough to
1438
1764
  * still be active — i.e. its `writeTimeout` (set only by addWrite, see the field comment) hasn't
@@ -1452,18 +1778,86 @@ function chainStillActive(txn) {
1452
1778
  }
1453
1779
  return false;
1454
1780
  }
1781
+ /**
1782
+ * Name a chain link still holding its native handle past the reporting threshold, and why the
1783
+ * branches below are not reaping it (harper#2471). Attribution only: it reads the recency clocks
1784
+ * those branches maintain rather than calling `chainStillActive`, which would decay `writeTimeout`
1785
+ * as a side effect, and it runs before them so it cannot reorder them.
1786
+ */
1787
+ function reportLongLivedLink(link, thresholdMs, now, reportBudget) {
1788
+ if (!link.transaction || link.handleOpenedAt === 0)
1789
+ return;
1790
+ const ageMs = now - link.handleOpenedAt;
1791
+ if (ageMs < thresholdMs)
1792
+ return;
1793
+ const states = [];
1794
+ if (link.sourceApply)
1795
+ states.push('source-apply');
1796
+ if (link.isReplay)
1797
+ states.push('replay');
1798
+ if (link.committing)
1799
+ states.push('commit-phase');
1800
+ if (link.open === exports.TRANSACTION_STATE.CLOSED)
1801
+ states.push('closed-with-open-iterators');
1802
+ if (monitorTick - link.writeTick <= 1)
1803
+ states.push('active');
1804
+ if (states.length === 0)
1805
+ states.push('over-limit');
1806
+ (0, longLivedTransactions_ts_1.reportLongLivedHolder)({
1807
+ databasePath: link.db?.rootStore?.path,
1808
+ nativeId: link.transaction.id,
1809
+ openedAt: link.handleOpenedAt,
1810
+ ageMs,
1811
+ databaseName: link.db?.rootStore?.databaseName,
1812
+ tableName: link.db?.name,
1813
+ countPendingWrites: () => {
1814
+ let pendingWrites = 0;
1815
+ for (const write of link.writes)
1816
+ if (write)
1817
+ pendingWrites++;
1818
+ return pendingWrites;
1819
+ },
1820
+ states,
1821
+ timeoutBudget: link.timeoutBudget,
1822
+ startedFrom: link.startedFrom,
1823
+ }, reportBudget);
1824
+ }
1825
+ /**
1826
+ * Report every link of this logical transaction that holds its own native handle. A blind write to a
1827
+ * second database attaches a handle to a `.next` link while only the root is supervised, so reporting
1828
+ * the entry alone names an id the sweep's line can never be joined to when the child is the holder.
1829
+ * Links that read are in `trackedTxns` and get their own visit from the tick.
1830
+ */
1831
+ function reportIfLongLived(txn, thresholdMs, now, reportBudget) {
1832
+ if (thresholdMs === 0)
1833
+ return;
1834
+ for (let link = txn; link; link = link.next) {
1835
+ if (link !== txn && trackedTxns.has(link))
1836
+ break;
1837
+ reportLongLivedLink(link, thresholdMs, now, reportBudget);
1838
+ }
1839
+ }
1455
1840
  function startMonitoringTxns() {
1456
1841
  timer = setInterval(function () {
1842
+ monitorTick++;
1843
+ const checkedCommitPhaseChains = new Set();
1844
+ const reportThresholdMs = (0, longLivedTransactions_ts_1.getReportThresholdMs)();
1845
+ (0, longLivedTransactions_ts_1.rebaseLongLivedTransactionReports)(reportThresholdMs);
1846
+ const reportBudget = (0, longLivedTransactions_ts_1.createLongLivedHolderReportBudget)(reportThresholdMs);
1847
+ const reportNow = performance.now();
1457
1848
  // Both registries, in sequence rather than as a union: a root can be in each (it read, and a
1458
1849
  // later link blind-wrote), and the membership check is cheaper than allocating per tick.
1459
1850
  for (const txn of trackedTxns)
1460
- monitorTransaction(txn);
1851
+ monitorTransaction(txn, checkedCommitPhaseChains, reportThresholdMs, reportNow, reportBudget);
1461
1852
  for (const txn of supervisedWriteRoots)
1462
1853
  if (!trackedTxns.has(txn))
1463
- monitorTransaction(txn);
1854
+ monitorTransaction(txn, checkedCommitPhaseChains, reportThresholdMs, reportNow, reportBudget);
1855
+ (0, longLivedTransactions_ts_1.finishLongLivedHolderReports)(reportBudget);
1464
1856
  }, txnExpiration).unref();
1465
- function monitorTransaction(txn) {
1857
+ function monitorTransaction(txn, checkedCommitPhaseChains, reportThresholdMs, reportNow, reportBudget) {
1858
+ reportIfLongLived(txn, reportThresholdMs, reportNow, reportBudget);
1466
1859
  {
1860
+ const commitChainHead = txn.commitChainHead ?? txn;
1467
1861
  // Decay write recency once per tick for every tracked link, independent of the `timeout`
1468
1862
  // branches below — a tracked link that keeps its own idle limit alive by reading must not
1469
1863
  // thereby keep chainStillActive believing it was written recently too.
@@ -1489,6 +1883,21 @@ function startMonitoringTxns() {
1489
1883
  harperLogger.warn?.(`Read iterators held a committed transaction's snapshot past the open-transaction limit; releasing it, from table: ${txn.db?.name + (url ? ' path: ' + url : '')}`);
1490
1884
  txn.releaseReadTxn();
1491
1885
  }
1886
+ else if (shouldSpareCommitPhase(txn, checkedCommitPhaseChains)) {
1887
+ // Parked in commit()'s pre-commit await — a `before`/`beforeIntermediate` hook, in practice a
1888
+ // blob's durable file write, which for a multi-tens-of-MB payload legitimately outruns the
1889
+ // limit. The write set is sealed and the caller is awaiting this commit, so the limit's
1890
+ // premise (the application is holding a transaction open) does not hold, and poisoning here
1891
+ // would unlink the blobs the write still references (issue #2062). The grace is bounded
1892
+ // because the transaction still pins a read snapshot: a source that stalls rather than
1893
+ // finishing falls through to the abort below once it runs out. A canonical-source apply or
1894
+ // replay is spared for as long as it takes: neither aborting it (harper-pro#348) nor the
1895
+ // force-commit below — which would durably commit a record whose blob file is still being
1896
+ // written — is acceptable, and their blob sources are bounded by the receive-side idle
1897
+ // watchdog instead.
1898
+ harperLogger.warn?.(`Transaction has been in its commit phase past the open-transaction limit, waiting on pre-commit work (e.g. a large blob write); letting it complete, from table: ${txn.db?.name + (url ? ' path: ' + url : '')}`, ...(txn.startedFrom ? [`was started from ${txn.startedFrom.resourceName}.${txn.startedFrom.method}`] : []));
1899
+ txn.timeout = Math.max(txnExpiration, txn.timeoutBudget ?? 0);
1900
+ }
1492
1901
  else if (txn.hasPendingWrites() && chainStillActive(txn)) {
1493
1902
  // A later link in the chain was written recently (writes re-arm only the link that
1494
1903
  // receives them, and a multi-store transaction can be writing database B while this
@@ -1507,7 +1916,7 @@ function startMonitoringTxns() {
1507
1916
  // those, keep the prior force-commit behavior below.
1508
1917
  harperLogger.error(`Transaction was open too long and has been aborted after exceeding the open-transaction limit, from table: ${txn.db?.name + (url ? ' path: ' + url : '')}`, ...(txn.startedFrom ? [`was started from ${txn.startedFrom.resourceName}.${txn.startedFrom.method}`] : []), ...(DEBUG_LONG_TXNS ? ['starting stack trace', txn.stackTraces] : []));
1509
1918
  try {
1510
- txn.abortDueToTimeout();
1919
+ commitChainHead.abortDueToTimeout();
1511
1920
  }
1512
1921
  catch (error) {
1513
1922
  harperLogger.debug?.(`Error aborting timed out transaction: ${error.message}`);
@@ -1546,6 +1955,11 @@ startMonitoringTxns();
1546
1955
  function resetReplayedWritesWarning() {
1547
1956
  replayedWritesWarned = false;
1548
1957
  }
1958
+ function setMaxOutstandingTxnDuration(ms) {
1959
+ const previous = MAX_OUTSTANDING_TXN_DURATION;
1960
+ MAX_OUTSTANDING_TXN_DURATION = ms;
1961
+ return previous;
1962
+ }
1549
1963
  /** Test seam: whether the monitor supervises this logical transaction for its writes. */
1550
1964
  function isWriteSupervised(txn) {
1551
1965
  return supervisedWriteRoots.has(txn);