@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
@@ -40,13 +40,36 @@ export function structuresWouldShrink(existing: any, updated: any): boolean {
40
40
  return false;
41
41
  }
42
42
 
43
- export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void> {
44
- if (!isMainThread) return; // ideally we don't do it like this, but for now this is predictable
45
- return new Promise((resolve) => {
43
+ /** The total wall-clock budget (ms) a replay may spend, as configured for this process. */
44
+ export function replayTimeBudgetMs(): number {
45
+ const configuredReplayTimeout = Number(envGet(CONFIG_PARAMS.REPLICATION_REPLAYTIMEOUT));
46
+ return configuredReplayTimeout > 0 ? configuredReplayTimeout : REPLAY_WALL_CLOCK_LIMIT_MS;
47
+ }
48
+
49
+ /**
50
+ * `electedReplayer` marks a caller that has already won a cross-thread election for this store —
51
+ * the branch claim (branchDatabase.ts) — and so may replay off the main thread. It also makes the
52
+ * replay strict: the promise settles (never hangs), and a failure to apply the tail — a commit or
53
+ * write error, a stall or wall-clock abort — rejects instead of quietly serving a rewound store.
54
+ * Undecodable entries and a torn tail stay tolerated in both modes: a crash tears the last frame of
55
+ * a log by construction, and end-of-log is the designed reading of it (see replayLogsGuards.ts). A
56
+ * **mid-log** break is different — entries behind it were acknowledged and are now quarantined — so
57
+ * an elected replay rejects on one rather than publish a branch as a trustworthy point-in-time copy
58
+ * over known lost writes; boot replay still logs it and continues (harper#2016, harper#2063).
59
+ */
60
+ export function replayLogs(rootStore: RocksDatabase, tables: any, electedReplayer?: boolean): Promise<void> {
61
+ if (!isMainThread && !electedReplayer) return Promise.resolve(); // ideally we don't do it like this, but for now this is predictable
62
+ return new Promise((resolve, reject) => {
46
63
  const acquired = rootStore.tryLock('replayLogs', async () => {
47
64
  resolve();
48
65
  });
49
- if (!acquired) return;
66
+ if (!acquired) {
67
+ // An elected replayer is the store's sole opener, so a held lock is a protocol violation;
68
+ // hanging its awaited promise would wedge the branch claim in CREATING. The boot-scan
69
+ // caller keeps the settle-on-unlock semantics (nothing awaits it).
70
+ if (electedReplayer) reject(new Error(`The replay lock for ${(rootStore as any).databaseName} is already held`));
71
+ return;
72
+ }
50
73
  // Shed transaction-log files already older than the audit retention window before
51
74
  // replaying. A node that crash-loops during recovery never reaches the steady-state
52
75
  // cleanup loop, so without this its aged backlog only grows and enlarges each subsequent
@@ -75,9 +98,13 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
75
98
  tableById.set(table.tableId, table);
76
99
  }
77
100
  // replay all the logs
78
- let transaction: DatabaseTransaction;
101
+ let transaction: DatabaseTransaction | undefined;
79
102
  let lastTimestamp = 0;
80
103
  let writes = 0;
104
+ // Writes staged on the currently-open transaction, so a discard can be taken back out of `writes`.
105
+ let stagedWrites = 0;
106
+ // Records dropped because a corrupt frame truncated the transaction they belong to.
107
+ let discardedWrites = 0;
81
108
  let skipped = 0;
82
109
  // Track forward progress so a backlog of unwritable entries can't grind the boot thread
83
110
  // forever (harper#1266). `noProgressRun` counts every entry processed without a successful
@@ -89,13 +116,33 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
89
116
  let lastProgressTime = replayStartTime;
90
117
  // Total wall-clock budget (ms) for replay, configurable via `replication.replayTimeout`;
91
118
  // falls back to the 10-minute default (harper#1316).
92
- const configuredReplayTimeout = Number(envGet(CONFIG_PARAMS.REPLICATION_REPLAYTIMEOUT));
93
- const replayTimeoutMs = configuredReplayTimeout > 0 ? configuredReplayTimeout : REPLAY_WALL_CLOCK_LIMIT_MS;
119
+ const replayTimeoutMs = replayTimeBudgetMs();
120
+ // Set on the first unrecoverable failure in elected mode; rejects below instead of publishing
121
+ // a store the replay knows is incomplete.
122
+ let strictFailure: Error | undefined;
123
+ const strictAbort = (error: Error, staged: DatabaseTransaction | undefined): void => {
124
+ try {
125
+ staged?.abort();
126
+ } catch (abortError) {
127
+ logger.warn('Error aborting a strict replay transaction', abortError);
128
+ }
129
+ strictFailure = error;
130
+ };
94
131
  const txnLog: RocksTransactionLogStore = (rootStore as any).auditStore;
95
- for (const auditRecord of txnLog.getRange({ startFromLastFlushed: true, readUncommitted: true }) as any) {
132
+ const entries = txnLog.getRange({
133
+ startFromLastFlushed: true,
134
+ readUncommitted: true,
135
+ trackCorruptTransactions: true,
136
+ });
137
+ for (const auditRecord of entries as any) {
96
138
  if (noProgressRun > 0 && shouldAbortStalledReplay(noProgressRun, performance.now() - lastProgressTime)) {
139
+ const stallDiagnostic = `Aborting transaction-log replay in ${(rootStore as any).databaseName} database: ${noProgressRun} consecutive audit entries with no successful write (${skipped} skipped as unrecoverable, ${writes} replayed so far). This backlog is making no forward progress and was blocking startup (harper#1266) — typically a peer transaction log whose values reference unresolvable shared structures (harper#1163), or a backlog for a dropped table.`;
140
+ if (electedReplayer) {
141
+ strictAbort(new Error(stallDiagnostic), transaction);
142
+ break;
143
+ }
97
144
  logger.fatal(
98
- `Aborting transaction-log replay in ${(rootStore as any).databaseName} database: ${noProgressRun} consecutive audit entries with no successful write (${skipped} skipped as unrecoverable, ${writes} replayed so far). This backlog is making no forward progress and was blocking startup (harper#1266) — typically a peer transaction log whose values reference unresolvable shared structures (harper#1163), or a backlog for a dropped table. Continuing boot without replaying the remainder; shed or relocate the oversized/undecodable peer transaction log(s), or re-clone this node, to recover the unreplayed data.`
145
+ `${stallDiagnostic} Continuing boot without replaying the remainder; shed or relocate the oversized/undecodable peer transaction log(s), or re-clone this node, to recover the unreplayed data.`
99
146
  );
100
147
  break;
101
148
  }
@@ -105,6 +152,7 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
105
152
  nodeId,
106
153
  recordId,
107
154
  version,
155
+ txnLogKey,
108
156
  residencyId,
109
157
  expiresAt,
110
158
  originatingOperation,
@@ -117,6 +165,11 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
117
165
  noProgressRun++;
118
166
  continue;
119
167
  }
168
+ if (type === 'evict') {
169
+ noProgressRun = 0;
170
+ lastProgressTime = performance.now();
171
+ continue;
172
+ }
120
173
  const Table = tableById.get(tableId);
121
174
  if (!Table) {
122
175
  // Entry for a table this node no longer has (dropped/foreign). Not an
@@ -165,14 +218,35 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
165
218
  warnedReplayHappening = true;
166
219
  console.warn('Harper was not properly shutdown, replaying transaction logs to synchronize database');
167
220
  }
168
- if (lastTimestamp !== version) {
169
- lastTimestamp = version;
221
+ // Transactions are delimited by the log key — which is also what `truncatedVersions` records —
222
+ // and each write is replayed at its own stored record version. The two differ for a source
223
+ // fill, and stamping such a record at the log key would move its version forward and make a
224
+ // later legitimate write in between look stale (harper#2411).
225
+ if (lastTimestamp !== txnLogKey) {
226
+ const torn = entries.corruptFrameStop.truncatedVersions.has(lastTimestamp);
227
+ lastTimestamp = txnLogKey;
170
228
  try {
171
- // commit the last transaction since we are starting a new one
172
- transaction?.directCommitSync();
229
+ // commit the last transaction since we are starting a new one, unless a corrupt
230
+ // frame swallowed the rest of it — half of a source transaction must never become
231
+ // durable, so it is dropped whole and stays in the log for a repaired retry
232
+ if (torn) {
233
+ writes -= stagedWrites;
234
+ discardedWrites += stagedWrites;
235
+ transaction?.abort();
236
+ } else transaction?.directCommitSync();
173
237
  } catch (error) {
174
- logger.error('Error committing replay transaction', error);
238
+ // directCommitSync aborts and detaches its transaction on failure; no cleanup here.
239
+ // The torn branch already backed stagedWrites out of writes before this try, so
240
+ // only a failed COMMIT (never applied) needs it backed out here too — otherwise a
241
+ // commit failure left `writes` counting records that never actually landed.
242
+ if (!torn) writes -= stagedWrites;
243
+ if (electedReplayer) {
244
+ strictFailure = error;
245
+ break;
246
+ }
247
+ logger.error(`Error ${torn ? 'discarding a torn' : 'committing'} replay transaction`, error);
175
248
  }
249
+ stagedWrites = 0;
176
250
  // Abort if replay has exceeded the total wall-clock budget even while making progress
177
251
  // (harper#1316, facet a). shouldAbortStalledReplay resets its counters on every write,
178
252
  // so a slow-but-progressing replay (deep out-of-order audit chain walk per entry) can
@@ -181,15 +255,18 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
181
255
  // is not yet staged, so aborting never tears a same-version (same source-transaction)
182
256
  // write batch in half. Re-clone to recover the unreplayed remainder.
183
257
  if (shouldAbortSlowReplay(performance.now() - replayStartTime, replayTimeoutMs)) {
184
- logger.fatal(
185
- `Aborting transaction-log replay in ${(rootStore as any).databaseName} database: replay has exceeded the wall-clock time limit (${writes} written, ${skipped} skipped). The transaction log contains a pathologically deep out-of-order write history that is too expensive to reconcile during boot (harper#1316). Re-clone this node from a healthy leader to recover the unreplayed data.`
186
- );
187
- transaction = undefined as any; // already committed above; nothing staged for the new version
258
+ const slowMessage = `Aborting transaction-log replay in ${(rootStore as any).databaseName} database: replay has exceeded the wall-clock time limit (${writes} written, ${skipped} skipped). The transaction log contains a pathologically deep out-of-order write history that is too expensive to reconcile during boot (harper#1316). Re-clone this node from a healthy leader to recover the unreplayed data.`;
259
+ transaction = undefined; // already committed above; nothing staged for the new version
260
+ if (electedReplayer) {
261
+ strictFailure = new Error(slowMessage);
262
+ break;
263
+ }
264
+ logger.fatal(slowMessage);
188
265
  break;
189
266
  }
190
267
  transaction = new DatabaseTransaction();
191
268
  transaction.db = primaryStore;
192
- transaction.timestamp = version;
269
+ transaction.timestamp = txnLogKey;
193
270
  // retries=1 routes operation.commit() through its retry path (no duplicate audit staging)
194
271
  transaction.retries = 1;
195
272
  // Explicit replay marker: skips schema validation (harper#1316) and makes save() stamp
@@ -198,8 +275,9 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
198
275
  transaction.isReplay = true;
199
276
  }
200
277
  context.transaction = transaction;
201
- const options = { context, residencyId, nodeId, originatingOperation };
278
+ const options = { context, residencyId, nodeId, originatingOperation, version };
202
279
  writes++;
280
+ stagedWrites++;
203
281
  switch (type) {
204
282
  case 'put':
205
283
  tableInstance._writeUpdate(recordId, record, true, options);
@@ -274,6 +352,10 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
274
352
  noProgressRun = 0;
275
353
  lastProgressTime = performance.now();
276
354
  } catch (err) {
355
+ if (electedReplayer) {
356
+ strictAbort(err, transaction);
357
+ break;
358
+ }
277
359
  // A write that threw made no forward progress either — count it toward the stall
278
360
  // bound so a continuous stream of throwing writes can't grind the boot thread
279
361
  // indefinitely (and the per-entry error log below can't spam unboundedly). harper#1266
@@ -283,18 +365,62 @@ export function replayLogs(rootStore: RocksDatabase, tables: any): Promise<void>
283
365
  });
284
366
  }
285
367
  }
286
- try {
287
- transaction?.directCommitSync();
288
- } catch (error) {
289
- logger.error('Error committing replay transaction', error);
368
+ const finalTorn = entries.corruptFrameStop.truncatedVersions.has(lastTimestamp);
369
+ if (!strictFailure) {
370
+ try {
371
+ if (finalTorn) {
372
+ writes -= stagedWrites;
373
+ discardedWrites += stagedWrites;
374
+ transaction?.abort();
375
+ } else transaction?.directCommitSync();
376
+ } catch (error) {
377
+ // directCommitSync aborts and detaches its transaction on failure; no cleanup here.
378
+ // Mirrors the interior version-boundary catch above: a failed commit never applied, so
379
+ // it must not stay counted in `writes`.
380
+ if (!finalTorn) writes -= stagedWrites;
381
+ if (electedReplayer) strictFailure = error;
382
+ logger.error(`Error ${finalTorn ? 'discarding a torn' : 'committing'} replay transaction`, error);
383
+ }
384
+ }
385
+ // `breaks` also counts a torn tail — the designed, benign reading of a crash's last frame, and
386
+ // the reporter already logged it at `warn`. Only a mid-log break lost entries, so it alone earns
387
+ // this quarantine/repair summary; duplicating it for a torn tail would tell an operator to
388
+ // repair or re-clone the node on every ordinary unclean shutdown.
389
+ if (entries.corruptFrameStop.midLogBreak) {
390
+ logger.error(
391
+ `Transaction-log replay in ${(rootStore as any).databaseName} database stopped at a corrupt entry after replaying ${writes} records. Every entry after the break is quarantined — neither replayed nor replicated — and ${discardedWrites} record(s) of the transaction the break truncated were discarded rather than applied in part. Repair the transaction log or re-clone this node to recover them.`
392
+ );
393
+ // electedReplayer must not resolve past known loss — see the doc comment above. Only set
394
+ // strictFailure if nothing has already failed the replay for an unrelated reason, so this
395
+ // diagnostic never shadows a more specific commit/write error.
396
+ if (electedReplayer && !strictFailure) {
397
+ strictFailure = new Error(
398
+ `Elected replay in ${(rootStore as any).databaseName} database stopped at a mid-log corrupt transaction-log frame; entries behind the break were acknowledged and are now quarantined. Refusing to publish a branch over known lost writes — repair the transaction log or re-clone this node.`
399
+ );
400
+ }
290
401
  }
291
402
  if (writes > 0) logger.warn(`Replayed ${writes} records in ${(rootStore as any).databaseName} database`);
292
403
  if (skipped > 0)
293
404
  logger.warn(
294
405
  `Skipped ${skipped} unrecoverable audit entries in ${(rootStore as any).databaseName} database during replay`
295
406
  );
296
- // we never actually release the lock because we only want to ever run one time
297
- // rootStore.unlock('replayLogs');
407
+ if (strictFailure) {
408
+ // A failed strict replay must be re-runnable: the branch claim resets for a retry, so the
409
+ // lock must not be what survives to wedge it. Only a COMPLETED replay keeps the lock
410
+ // forever (the once-per-boot guarantee). Reject BEFORE unlocking: unlock wakes tryLock
411
+ // callbacks — including this holder's own resolve() — and the first settle must be the
412
+ // rejection, or a failed replay reads as success.
413
+ reject(strictFailure);
414
+ try {
415
+ rootStore.unlock('replayLogs');
416
+ } catch (unlockError) {
417
+ logger.warn('Error releasing the replay lock after a failed replay', unlockError);
418
+ }
419
+ } else {
420
+ // we never actually release the lock because we only want to ever run one time
421
+ // rootStore.unlock('replayLogs');
422
+ resolve();
423
+ }
298
424
  });
299
425
  }
300
426
  function asBinary(buffer) {
@@ -132,16 +132,66 @@ export function shouldAbortSlowReplay(totalElapsedMs: number, timeLimitMs = REPL
132
132
  }
133
133
 
134
134
  /**
135
- * Wraps a transaction-log query iterator so a corrupt/torn frame ends that log's iteration
136
- * cleanly instead of escaping as an uncaughtException. rocksdb-js throws a bounded RangeError
137
- * when an entry's framing is broken; framing loss means the next entry can't be located, so the
138
- * frame marks end-of-log (entries before it were already yielded) and startup replay /
139
- * replication broadcast continue. `onCorruptFrame` fires once, latched — kept a callback (not a
140
- * direct log) so this module stays out of the Harper module graph and is unit-testable.
135
+ * A corrupt transaction-log frame from rocksdb-js. `resyncPosition` is set only when intact entries
136
+ * follow the break, which is what distinguishes lost entries from a merely truncated tail; its
137
+ * absence is also all that any rocksdb-js predating that field can report.
138
+ */
139
+ export type CorruptFrameError = RangeError & {
140
+ logId?: number | null;
141
+ position?: number | null;
142
+ resyncPosition?: number | null;
143
+ unreadableBytes?: number | null;
144
+ };
145
+
146
+ /**
147
+ * Corrupt frames hit by one `getRange` call, shared by its per-log iterators.
148
+ *
149
+ * `truncatedVersions` is what a consumer has to act on: a break destroys the framing after the last
150
+ * entry the broken log yielded, and whether the entries it swallowed continued that entry's version
151
+ * is exactly what can no longer be read — UNLESS that last entry's own `endTxn` already closed its
152
+ * transaction, in which case nothing of it was left open to swallow. That version's transaction is
153
+ * therefore incomplete only when it wasn't already known-closed, and replay must discard it rather
154
+ * than commit the part of it that was still readable. A log that broke before yielding anything
155
+ * truncates no transaction.
156
+ *
157
+ * `midLogBreak` is coarser: true once any break in this range left intact entries unreadable behind
158
+ * it (see {@link isMidLogBreak}), regardless of which version they belonged to. A consumer that must
159
+ * never serve a range with lost entries — an elected branch replay publishing itself as a trustworthy
160
+ * point-in-time copy — rejects on this rather than on `truncatedVersions`, since a mid-log break can
161
+ * strand entries whose version this range never even attributes to one log (harper#2016, #2063).
162
+ */
163
+ export interface CorruptFrameStop {
164
+ breaks: number;
165
+ truncatedVersions: Set<number>;
166
+ midLogBreak: boolean;
167
+ }
168
+
169
+ /**
170
+ * Whether a corrupt frame is a mid-log break — intact entries followed it, so entries were lost
171
+ * rather than the log merely being torn at its tail. Shared by the reporter below and by
172
+ * `RocksTransactionLogStore.getRange`'s `CorruptFrameStop.midLogBreak`, so the two can't drift on
173
+ * what counts as a mid-log break.
174
+ */
175
+ export function isMidLogBreak(error: CorruptFrameError): boolean {
176
+ return error.resyncPosition != null;
177
+ }
178
+
179
+ /**
180
+ * Wraps a transaction-log query iterator so a corrupt/torn frame ends that log's iteration cleanly
181
+ * instead of escaping as an uncaughtException.
182
+ *
183
+ * Iteration stops at the break whether or not intact entries follow it. Resuming past a mid-log
184
+ * break would recover those entries, but a transaction log carries no frame-level transaction
185
+ * boundaries: replay groups equal-version entries into one source transaction, so skipping a frame
186
+ * inside such a group applies and checkpoints the surviving subset of a transaction that never
187
+ * committed that way at the source. Availability loss is visible and recoverable; a silently torn
188
+ * transaction is neither. Recovery is deferred until the engine can resume at a proven boundary
189
+ * (harper#2016, harper#2063); `resyncPosition` is used only to report the break as lost entries
190
+ * rather than as a truncated tail.
141
191
  */
142
192
  export function endIteratorOnCorruptFrame<T>(
143
193
  iterator: Iterator<T>,
144
- onCorruptFrame: (error: RangeError) => void
194
+ onCorruptFrame: (error: CorruptFrameError) => void
145
195
  ): IterableIterator<T> {
146
196
  let stopped = false;
147
197
  return {
@@ -157,7 +207,7 @@ export function endIteratorOnCorruptFrame<T>(
157
207
  // version-dependent (1.4.2 added hex offsets). Anything else re-throws.
158
208
  if (!(error instanceof RangeError)) throw error;
159
209
  stopped = true;
160
- onCorruptFrame(error);
210
+ onCorruptFrame(error as CorruptFrameError);
161
211
  return { done: true, value: undefined };
162
212
  }
163
213
  },
@@ -175,3 +225,116 @@ export function endIteratorOnCorruptFrame<T>(
175
225
  },
176
226
  };
177
227
  }
228
+
229
+ /**
230
+ * A corrupt frame, accumulated for the life of the process. The same frame is re-encountered by
231
+ * every reader until each consumer's resume cursor has passed it, so this is deduplicated by
232
+ * location and the repeats become a count.
233
+ */
234
+ export interface CorruptFrameReport {
235
+ log: string;
236
+ logId?: number;
237
+ position?: number;
238
+ /** Intact entries followed the break, so entries were lost rather than merely truncated. */
239
+ midLog: boolean;
240
+ /** Extent of the unreadable region, when the engine reports it; 0 when nothing valid follows it. */
241
+ unreadableBytes: number;
242
+ firstSeen: number;
243
+ lastSeen: number;
244
+ occurrences: number;
245
+ }
246
+
247
+ /** Distinct break sites retained. One physical corruption yields one site, so this is generous. */
248
+ export const MAX_CORRUPT_FRAME_REPORTS = 256;
249
+
250
+ // Re-encounters move a site to the end, so the first key is the least recently seen. Full means
251
+ // evicting that one rather than refusing a new site, which could not then be deduplicated.
252
+ const corruptFrameReports = new Map<string, CorruptFrameReport>();
253
+ let evictedCorruptFrameReports = 0;
254
+
255
+ /**
256
+ * Every corrupt frame seen by this worker. This is not yet consumed by cluster/health status;
257
+ * callers must aggregate it across worker threads before exposing a node-wide signal.
258
+ *
259
+ * Mid-log breaks are immediately logged at error level even without that consumer.
260
+ */
261
+ export function getCorruptFrameReports(): CorruptFrameReport[] {
262
+ return [...corruptFrameReports.values()];
263
+ }
264
+
265
+ /** Break sites evicted because {@link MAX_CORRUPT_FRAME_REPORTS} was reached. */
266
+ export function getEvictedCorruptFrameReportCount(): number {
267
+ return evictedCorruptFrameReports;
268
+ }
269
+
270
+ export function clearCorruptFrameReports() {
271
+ corruptFrameReports.clear();
272
+ evictedCorruptFrameReports = 0;
273
+ }
274
+
275
+ // `logId`/`position` are absent on any rocksdb-js predating the resync support, and every break on
276
+ // a stream would then collapse onto one key — folding genuinely different corruptions into a single
277
+ // count that only ever logs once. The message carries the offset and file in text, so it separates
278
+ // them when the fields can't.
279
+ function corruptFrameKey(logName: string, error: CorruptFrameError): string {
280
+ const { logId, position } = error;
281
+ return logId != null && position != null
282
+ ? `${logName}\u0000${logId}:${position}`
283
+ : `${logName}\u0000${error.message}`;
284
+ }
285
+
286
+ /**
287
+ * Records a corrupt frame and logs it once per distinct break.
288
+ *
289
+ * A mid-log break is an `error`, not a `warn`: entries after it were acknowledged and are now
290
+ * quarantined behind it. Severity follows the break's own shape, never this pass's outcome — every
291
+ * pass stops, so keying on that would report the #2063 signature with the benign torn-tail `warn`.
292
+ * A site first seen as a torn tail can escalate later, since only a rocksdb-js that reports
293
+ * `resyncPosition` can tell the two apart.
294
+ */
295
+ export function createCorruptFrameReporter(logger: {
296
+ warn: (message: string, error?: unknown) => void;
297
+ error: (message: string, error?: unknown) => void;
298
+ }) {
299
+ return (logName: string) => (error: CorruptFrameError) => {
300
+ const midLog = isMidLogBreak(error);
301
+ const unreadableBytes = error.unreadableBytes ?? 0;
302
+ const now = Date.now();
303
+ const key = corruptFrameKey(logName, error);
304
+ const existing = corruptFrameReports.get(key);
305
+ if (existing) {
306
+ corruptFrameReports.delete(key);
307
+ corruptFrameReports.set(key, existing);
308
+ existing.occurrences++;
309
+ existing.lastSeen = now;
310
+ if (!midLog || existing.midLog) return;
311
+ existing.midLog = true;
312
+ existing.unreadableBytes = unreadableBytes;
313
+ } else {
314
+ if (corruptFrameReports.size >= MAX_CORRUPT_FRAME_REPORTS) {
315
+ corruptFrameReports.delete(corruptFrameReports.keys().next().value);
316
+ evictedCorruptFrameReports++;
317
+ }
318
+ corruptFrameReports.set(key, {
319
+ log: logName,
320
+ logId: error.logId ?? undefined,
321
+ position: error.position ?? undefined,
322
+ midLog,
323
+ unreadableBytes,
324
+ firstSeen: now,
325
+ lastSeen: now,
326
+ occurrences: 1,
327
+ });
328
+ }
329
+ if (midLog) {
330
+ logger.error(
331
+ `Corrupt entry in transaction log "${logName}"; ${unreadableBytes} byte(s) are unreadable and the entries within them are lost. ` +
332
+ 'Intact entries follow the break, but reading stops there rather than skipping the frame, which could tear a source transaction: ' +
333
+ 'they are quarantined until the log is repaired or this node is re-cloned, and they are neither replayed nor replicated meanwhile.',
334
+ error
335
+ );
336
+ } else {
337
+ logger.warn(`Stopping transaction log "${logName}" at a corrupt entry during replay`, error);
338
+ }
339
+ };
340
+ }
@@ -0,0 +1,77 @@
1
+ import { onRemovedDB } from './databases.ts';
2
+ import { logger } from '../utility/logging/logger.ts';
3
+ import { contextStorage } from './transaction.ts';
4
+
5
+ export interface ReplicatedApplyFailure {
6
+ readonly database: string;
7
+ readonly table?: string;
8
+ readonly nodeId: number;
9
+ readonly position: number;
10
+ readonly localTime?: number;
11
+ readonly error: unknown;
12
+ }
13
+
14
+ export type ReplicatedApplyFailureListener = (failure: ReplicatedApplyFailure) => void | Promise<void>;
15
+
16
+ const listenersByDatabase = new Map<string, Set<ReplicatedApplyFailureListener>>();
17
+ let watchingDatabaseRemoval = false;
18
+
19
+ export function registerReplicatedApplyFailureListener(
20
+ database: string,
21
+ listener: ReplicatedApplyFailureListener
22
+ ): void {
23
+ if (!watchingDatabaseRemoval) {
24
+ onRemovedDB((database) => listenersByDatabase.delete(database));
25
+ watchingDatabaseRemoval = true;
26
+ }
27
+ let listeners = listenersByDatabase.get(database);
28
+ if (!listeners) listenersByDatabase.set(database, (listeners = new Set()));
29
+ listeners.add(listener);
30
+ }
31
+
32
+ export function unregisterReplicatedApplyFailureListener(
33
+ database: string,
34
+ listener: ReplicatedApplyFailureListener
35
+ ): void {
36
+ const listeners = listenersByDatabase.get(database);
37
+ listeners?.delete(listener);
38
+ if (listeners?.size === 0) listenersByDatabase.delete(database);
39
+ }
40
+
41
+ export async function notifyReplicatedApplyFailure(
42
+ database: string,
43
+ event: { table?: string; nodeId?: number; localTime?: number },
44
+ position: number | undefined,
45
+ error: unknown,
46
+ table?: string
47
+ ): Promise<void> {
48
+ if (listenersByDatabase.size === 0) return;
49
+ try {
50
+ if (typeof event?.nodeId !== 'number' || typeof position !== 'number') return;
51
+ const listeners = listenersByDatabase.get(database);
52
+ if (!listeners) return;
53
+ const failure: ReplicatedApplyFailure = Object.freeze({
54
+ database,
55
+ table: event.table ?? table,
56
+ nodeId: event.nodeId,
57
+ position,
58
+ localTime: event.localTime,
59
+ error,
60
+ });
61
+ for (const listener of [...listeners]) {
62
+ try {
63
+ await contextStorage.exit(() => listener(failure));
64
+ } catch (error) {
65
+ logListenerFailure(database, error);
66
+ }
67
+ }
68
+ } catch (error) {
69
+ logListenerFailure(database, error);
70
+ }
71
+ }
72
+
73
+ function logListenerFailure(database: string, error: unknown): void {
74
+ try {
75
+ logger.error?.('replicated apply failure listener failed', database, error);
76
+ } catch {}
77
+ }
@@ -1,5 +1,5 @@
1
1
  import { isAbsolute, join } from 'node:path';
2
- import { getWorkerIndex } from '../../server/threads/manageThreads.js';
2
+ import { isApplicationPrimaryWorker } from '../../server/threads/manageThreads.js';
3
3
  import { ClientError } from '../../utility/errors/hdbError.ts';
4
4
  import { convertToMS } from '../../utility/common_utils.ts';
5
5
  import harperLogger from '../../utility/logging/harper_logger.ts';
@@ -94,12 +94,12 @@ export async function handleApplication(scope): Promise<void> {
94
94
  }
95
95
 
96
96
  // Activation gates: one worker owns scheduling for the whole node
97
- // (getWorkerIndex() === 0 is correct in every threading mode, including
97
+ // (the application's primary worker is correct in every threading mode, including
98
98
  // threads:0 where the main thread acts as worker 0), and a deploy
99
99
  // pre-flight validation scope must never touch the live engine — it can
100
100
  // share a running component's identity, so registering from it would
101
- // displace the real component's jobs (review finding).
102
- if (getWorkerIndex() !== 0) {
101
+ // displace the real component's jobs.
102
+ if (!isApplicationPrimaryWorker(scope.applicationScope?.name)) {
103
103
  schedulerLogger.debug?.('Scheduler config validated; activation skipped on non-primary worker');
104
104
  return;
105
105
  }