@harperfast/harper 5.3.0-alpha.1 → 5.3.0-beta.2

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 (347) hide show
  1. package/bin/cliOperations.ts +12 -0
  2. package/bin/restart.ts +66 -6
  3. package/components/Application.ts +1134 -112
  4. package/components/DESIGN.md +421 -0
  5. package/components/OptionsWatcher.ts +368 -102
  6. package/components/Scope.ts +20 -1
  7. package/components/componentLoader.ts +43 -4
  8. package/components/deploymentOperations.ts +4 -1
  9. package/components/deploymentRecorder.ts +9 -2
  10. package/components/mcp/DESIGN.md +109 -0
  11. package/components/mcp/audit.ts +21 -17
  12. package/components/operations.js +284 -52
  13. package/components/operationsValidation.js +49 -2
  14. package/components/packageComponent.ts +25 -1
  15. package/components/requestRestart.ts +11 -0
  16. package/config/DESIGN.md +306 -0
  17. package/config/RootConfigWatcher.ts +191 -37
  18. package/config/configReadRetry.ts +62 -0
  19. package/config/configUtils.ts +78 -26
  20. package/config/parseConfigFile.ts +34 -0
  21. package/config/readConfigFileSync.ts +44 -0
  22. package/config/watcherArming.ts +59 -0
  23. package/config-root.schema.json +4 -0
  24. package/dataLayer/DESIGN.md +179 -0
  25. package/dataLayer/harperBridge/ResourceBridge.ts +28 -2
  26. package/dataLayer/restoreMarker.ts +92 -25
  27. package/dist/bin/cliOperations.js +13 -0
  28. package/dist/bin/cliOperations.js.map +1 -1
  29. package/dist/bin/restart.js +42 -6
  30. package/dist/bin/restart.js.map +1 -1
  31. package/dist/components/Application.d.ts +104 -9
  32. package/dist/components/Application.js +954 -102
  33. package/dist/components/Application.js.map +1 -1
  34. package/dist/components/OptionsWatcher.d.ts +4 -1
  35. package/dist/components/OptionsWatcher.js +378 -104
  36. package/dist/components/OptionsWatcher.js.map +1 -1
  37. package/dist/components/Scope.js +15 -1
  38. package/dist/components/Scope.js.map +1 -1
  39. package/dist/components/componentLoader.js +35 -3
  40. package/dist/components/componentLoader.js.map +1 -1
  41. package/dist/components/deploymentOperations.js +4 -1
  42. package/dist/components/deploymentOperations.js.map +1 -1
  43. package/dist/components/deploymentRecorder.d.ts +4 -2
  44. package/dist/components/deploymentRecorder.js +1 -0
  45. package/dist/components/deploymentRecorder.js.map +1 -1
  46. package/dist/components/mcp/audit.d.ts +2 -1
  47. package/dist/components/mcp/audit.js +21 -17
  48. package/dist/components/mcp/audit.js.map +1 -1
  49. package/dist/components/operations.d.ts +28 -0
  50. package/dist/components/operations.js +263 -54
  51. package/dist/components/operations.js.map +1 -1
  52. package/dist/components/operationsValidation.js +48 -2
  53. package/dist/components/operationsValidation.js.map +1 -1
  54. package/dist/components/packageComponent.js +24 -0
  55. package/dist/components/packageComponent.js.map +1 -1
  56. package/dist/components/requestRestart.d.ts +1 -0
  57. package/dist/components/requestRestart.js +7 -0
  58. package/dist/components/requestRestart.js.map +1 -1
  59. package/dist/config/RootConfigWatcher.d.ts +2 -0
  60. package/dist/config/RootConfigWatcher.js +189 -35
  61. package/dist/config/RootConfigWatcher.js.map +1 -1
  62. package/dist/config/configReadRetry.d.ts +8 -0
  63. package/dist/config/configReadRetry.js +62 -0
  64. package/dist/config/configReadRetry.js.map +1 -0
  65. package/dist/config/configUtils.d.ts +10 -9
  66. package/dist/config/configUtils.js +63 -27
  67. package/dist/config/configUtils.js.map +1 -1
  68. package/dist/config/parseConfigFile.d.ts +4 -0
  69. package/dist/config/parseConfigFile.js +35 -0
  70. package/dist/config/parseConfigFile.js.map +1 -0
  71. package/dist/config/readConfigFileSync.d.ts +1 -0
  72. package/dist/config/readConfigFileSync.js +47 -0
  73. package/dist/config/readConfigFileSync.js.map +1 -0
  74. package/dist/config/watcherArming.d.ts +15 -0
  75. package/dist/config/watcherArming.js +59 -0
  76. package/dist/config/watcherArming.js.map +1 -0
  77. package/dist/dataLayer/harperBridge/ResourceBridge.js +21 -2
  78. package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
  79. package/dist/dataLayer/restoreMarker.d.ts +21 -8
  80. package/dist/dataLayer/restoreMarker.js +94 -27
  81. package/dist/dataLayer/restoreMarker.js.map +1 -1
  82. package/dist/index.d.ts +2 -0
  83. package/dist/index.js +9 -1
  84. package/dist/index.js.map +1 -1
  85. package/dist/json/systemSchema.json +3 -0
  86. package/dist/resources/DatabaseTransaction.d.ts +25 -0
  87. package/dist/resources/DatabaseTransaction.js +224 -18
  88. package/dist/resources/DatabaseTransaction.js.map +1 -1
  89. package/dist/resources/LMDBTransaction.d.ts +2 -1
  90. package/dist/resources/LMDBTransaction.js +22 -3
  91. package/dist/resources/LMDBTransaction.js.map +1 -1
  92. package/dist/resources/PrimaryRocksDatabase.js +22 -6
  93. package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
  94. package/dist/resources/RecordEncoder.d.ts +1 -1
  95. package/dist/resources/RecordEncoder.js +46 -10
  96. package/dist/resources/RecordEncoder.js.map +1 -1
  97. package/dist/resources/Resource.js +97 -13
  98. package/dist/resources/Resource.js.map +1 -1
  99. package/dist/resources/ResourceInterface.d.ts +8 -0
  100. package/dist/resources/RocksIndexStore.js +2 -1
  101. package/dist/resources/RocksIndexStore.js.map +1 -1
  102. package/dist/resources/RocksTransactionLogStore.d.ts +10 -0
  103. package/dist/resources/RocksTransactionLogStore.js +104 -33
  104. package/dist/resources/RocksTransactionLogStore.js.map +1 -1
  105. package/dist/resources/Table.d.ts +58 -7
  106. package/dist/resources/Table.js +1143 -348
  107. package/dist/resources/Table.js.map +1 -1
  108. package/dist/resources/analytics/write.d.ts +3 -0
  109. package/dist/resources/analytics/write.js +49 -16
  110. package/dist/resources/analytics/write.js.map +1 -1
  111. package/dist/resources/auditStore.d.ts +170 -0
  112. package/dist/resources/auditStore.js +457 -11
  113. package/dist/resources/auditStore.js.map +1 -1
  114. package/dist/resources/crdt.d.ts +10 -0
  115. package/dist/resources/crdt.js +22 -0
  116. package/dist/resources/crdt.js.map +1 -1
  117. package/dist/resources/dataLoader.js +3 -4
  118. package/dist/resources/dataLoader.js.map +1 -1
  119. package/dist/resources/databases.d.ts +16 -13
  120. package/dist/resources/databases.js +625 -177
  121. package/dist/resources/databases.js.map +1 -1
  122. package/dist/resources/derivedIndexRegistry.d.ts +5 -0
  123. package/dist/resources/derivedIndexRegistry.js +68 -0
  124. package/dist/resources/derivedIndexRegistry.js.map +1 -0
  125. package/dist/resources/derivedIndexRuntime.d.ts +215 -0
  126. package/dist/resources/derivedIndexRuntime.js +2027 -0
  127. package/dist/resources/derivedIndexRuntime.js.map +1 -0
  128. package/dist/resources/graphql.js +3 -2
  129. package/dist/resources/graphql.js.map +1 -1
  130. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +102 -9
  131. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +867 -39
  132. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
  133. package/dist/resources/indexes/fullTextDerivedIndex.d.ts +81 -0
  134. package/dist/resources/indexes/fullTextDerivedIndex.js +1004 -0
  135. package/dist/resources/indexes/fullTextDerivedIndex.js.map +1 -0
  136. package/dist/resources/indexes/fullTextNativeBinding.d.ts +78 -0
  137. package/dist/resources/indexes/fullTextNativeBinding.js +85 -0
  138. package/dist/resources/indexes/fullTextNativeBinding.js.map +1 -0
  139. package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
  140. package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
  141. package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
  142. package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
  143. package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
  144. package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
  145. package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.d.ts +24 -0
  146. package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js +149 -0
  147. package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js.map +1 -0
  148. package/dist/resources/nodeIdMapping.d.ts +5 -0
  149. package/dist/resources/nodeIdMapping.js +49 -0
  150. package/dist/resources/nodeIdMapping.js.map +1 -1
  151. package/dist/resources/recordLock.d.ts +47 -4
  152. package/dist/resources/recordLock.js +138 -7
  153. package/dist/resources/recordLock.js.map +1 -1
  154. package/dist/resources/recordLockCoordinator.d.ts +557 -0
  155. package/dist/resources/recordLockCoordinator.js +2597 -0
  156. package/dist/resources/recordLockCoordinator.js.map +1 -0
  157. package/dist/resources/replayLogs.js +5 -0
  158. package/dist/resources/replayLogs.js.map +1 -1
  159. package/dist/resources/replicatedApplyFailure.d.ts +16 -0
  160. package/dist/resources/replicatedApplyFailure.js +63 -0
  161. package/dist/resources/replicatedApplyFailure.js.map +1 -0
  162. package/dist/resources/scheduler/scheduler.js +3 -3
  163. package/dist/resources/scheduler/scheduler.js.map +1 -1
  164. package/dist/resources/search.d.ts +10 -4
  165. package/dist/resources/search.js +160 -40
  166. package/dist/resources/search.js.map +1 -1
  167. package/dist/resources/tracked.d.ts +5 -1
  168. package/dist/resources/tracked.js +74 -23
  169. package/dist/resources/tracked.js.map +1 -1
  170. package/dist/resources/transactionBroadcast.js +4 -6
  171. package/dist/resources/transactionBroadcast.js.map +1 -1
  172. package/dist/security/auth.js +59 -23
  173. package/dist/security/auth.js.map +1 -1
  174. package/dist/security/deferredAuthentication.d.ts +11 -0
  175. package/dist/security/deferredAuthentication.js +25 -3
  176. package/dist/security/deferredAuthentication.js.map +1 -1
  177. package/dist/security/jsLoader.js +9 -4
  178. package/dist/security/jsLoader.js.map +1 -1
  179. package/dist/server/REST.js +39 -5
  180. package/dist/server/REST.js.map +1 -1
  181. package/dist/server/http.d.ts +5 -1
  182. package/dist/server/http.js +34 -2
  183. package/dist/server/http.js.map +1 -1
  184. package/dist/server/mqtt.js +5 -1
  185. package/dist/server/mqtt.js.map +1 -1
  186. package/dist/server/serverHelpers/Headers.d.ts +2 -0
  187. package/dist/server/serverHelpers/Headers.js +6 -0
  188. package/dist/server/serverHelpers/Headers.js.map +1 -1
  189. package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
  190. package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
  191. package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
  192. package/dist/server/serverHelpers/Request.d.ts +5 -10
  193. package/dist/server/serverHelpers/Request.js +38 -136
  194. package/dist/server/serverHelpers/Request.js.map +1 -1
  195. package/dist/server/serverHelpers/contentTypes.d.ts +2 -0
  196. package/dist/server/serverHelpers/contentTypes.js +189 -15
  197. package/dist/server/serverHelpers/contentTypes.js.map +1 -1
  198. package/dist/server/serverHelpers/serverUtilities.d.ts +3 -3
  199. package/dist/server/serverHelpers/serverUtilities.js +110 -20
  200. package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
  201. package/dist/server/serverHelpers/uwsServer.js +4 -1
  202. package/dist/server/serverHelpers/uwsServer.js.map +1 -1
  203. package/dist/server/serverHelpers/webSocketCloseReason.d.ts +2 -0
  204. package/dist/server/serverHelpers/webSocketCloseReason.js +29 -0
  205. package/dist/server/serverHelpers/webSocketCloseReason.js.map +1 -0
  206. package/dist/server/storageReclamation.js +1 -1
  207. package/dist/server/storageReclamation.js.map +1 -1
  208. package/dist/server/threads/isolatedApplications.d.ts +47 -0
  209. package/dist/server/threads/isolatedApplications.js +171 -0
  210. package/dist/server/threads/isolatedApplications.js.map +1 -0
  211. package/dist/server/threads/logRotationTransport.d.ts +1 -0
  212. package/dist/server/threads/logRotationTransport.js +33 -0
  213. package/dist/server/threads/logRotationTransport.js.map +1 -0
  214. package/dist/server/threads/manageThreads.d.ts +64 -6
  215. package/dist/server/threads/manageThreads.js +261 -12
  216. package/dist/server/threads/manageThreads.js.map +1 -1
  217. package/dist/server/threads/socketRouter.d.ts +1 -0
  218. package/dist/server/threads/socketRouter.js +196 -13
  219. package/dist/server/threads/socketRouter.js.map +1 -1
  220. package/dist/server/threads/threadServer.js +30 -7
  221. package/dist/server/threads/threadServer.js.map +1 -1
  222. package/dist/utility/errors/hdbError.d.ts +24 -0
  223. package/dist/utility/errors/hdbError.js +58 -1
  224. package/dist/utility/errors/hdbError.js.map +1 -1
  225. package/dist/utility/hdbTerms.d.ts +2 -0
  226. package/dist/utility/hdbTerms.js +2 -0
  227. package/dist/utility/hdbTerms.js.map +1 -1
  228. package/dist/utility/logging/harper_logger.js +218 -38
  229. package/dist/utility/logging/harper_logger.js.map +1 -1
  230. package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
  231. package/dist/utility/logging/logGenerationCoordinator.js +184 -0
  232. package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
  233. package/dist/utility/logging/logRotation.d.ts +46 -0
  234. package/dist/utility/logging/logRotation.js +365 -0
  235. package/dist/utility/logging/logRotation.js.map +1 -0
  236. package/dist/utility/logging/logRotator.d.ts +1 -1
  237. package/dist/utility/logging/logRotator.js +172 -92
  238. package/dist/utility/logging/logRotator.js.map +1 -1
  239. package/dist/utility/npmUtilities.js +6 -4
  240. package/dist/utility/npmUtilities.js.map +1 -1
  241. package/dist/utility/watcherFallback.d.ts +0 -45
  242. package/dist/utility/watcherFallback.js +1 -125
  243. package/dist/utility/watcherFallback.js.map +1 -1
  244. package/dist/validation/configValidator.js +6 -3
  245. package/dist/validation/configValidator.js.map +1 -1
  246. package/index.ts +9 -0
  247. package/json/systemSchema.json +3 -0
  248. package/npm-shrinkwrap.json +177 -87
  249. package/package.json +13 -5
  250. package/resources/DESIGN.md +689 -19
  251. package/resources/DatabaseTransaction.ts +230 -17
  252. package/resources/LMDBTransaction.ts +21 -3
  253. package/resources/PrimaryRocksDatabase.ts +20 -7
  254. package/resources/RecordEncoder.ts +52 -10
  255. package/resources/Resource.ts +97 -13
  256. package/resources/ResourceInterface.ts +8 -0
  257. package/resources/RocksIndexStore.ts +2 -1
  258. package/resources/RocksTransactionLogStore.ts +111 -31
  259. package/resources/Table.ts +1273 -396
  260. package/resources/analytics/DESIGN.md +38 -0
  261. package/resources/analytics/write.ts +50 -17
  262. package/resources/auditStore.ts +460 -11
  263. package/resources/crdt.ts +22 -0
  264. package/resources/dataLoader.ts +3 -4
  265. package/resources/databases.ts +611 -147
  266. package/resources/derivedIndexRegistry.ts +56 -0
  267. package/resources/derivedIndexRuntime.ts +2292 -0
  268. package/resources/graphql.ts +3 -2
  269. package/resources/indexes/DESIGN.md +833 -0
  270. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +924 -46
  271. package/resources/indexes/fullTextDerivedIndex.ts +1165 -0
  272. package/resources/indexes/fullTextNativeBinding.ts +146 -0
  273. package/resources/indexes/hnswDerivedIndex.ts +531 -0
  274. package/resources/indexes/hnswPlaneBinding.ts +174 -0
  275. package/resources/indexes/nativeFullTextDerivedIndexLifecycle.ts +181 -0
  276. package/resources/nodeIdMapping.ts +50 -0
  277. package/resources/record-locks.md +1407 -0
  278. package/resources/recordLock.ts +173 -7
  279. package/resources/recordLockCoordinator.ts +3082 -0
  280. package/resources/replayLogs.ts +5 -0
  281. package/resources/replicatedApplyFailure.ts +77 -0
  282. package/resources/scheduler/DESIGN.md +40 -0
  283. package/resources/scheduler/scheduler.ts +4 -4
  284. package/resources/search.ts +169 -49
  285. package/resources/tracked.ts +73 -22
  286. package/resources/transactionBroadcast.ts +4 -4
  287. package/security/DESIGN.md +175 -0
  288. package/security/auth.ts +53 -24
  289. package/security/deferredAuthentication.ts +24 -2
  290. package/security/jsLoader.ts +9 -4
  291. package/server/DESIGN.md +275 -0
  292. package/server/REST.ts +42 -6
  293. package/server/http.ts +34 -2
  294. package/server/mqtt.ts +6 -4
  295. package/server/serverHelpers/Headers.ts +5 -1
  296. package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
  297. package/server/serverHelpers/Request.ts +33 -131
  298. package/server/serverHelpers/contentTypes.ts +188 -15
  299. package/server/serverHelpers/serverUtilities.ts +157 -27
  300. package/server/serverHelpers/uwsServer.ts +4 -1
  301. package/server/serverHelpers/webSocketCloseReason.ts +25 -0
  302. package/server/storageReclamation.ts +2 -2
  303. package/server/threads/isolatedApplications.ts +157 -0
  304. package/server/threads/logRotationTransport.ts +40 -0
  305. package/server/threads/manageThreads.js +254 -12
  306. package/server/threads/socketRouter.ts +217 -11
  307. package/server/threads/threadServer.js +30 -7
  308. package/studio/web/assets/{Chat-BnCBegQz.js → Chat-DADFFGe_.js} +1 -1
  309. package/studio/web/assets/{FloatingChat-CoDW1ySS.js → FloatingChat-D_mI-rZ7.js} +3 -3
  310. package/studio/web/assets/{apiToken-Bwk5BLXW.js → apiToken-c2NiSDHa.js} +1 -1
  311. package/studio/web/assets/{applications-DHxGi7JH.js → applications-DktUqh7G.js} +1 -1
  312. package/studio/web/assets/{cssMode-s0cWI-_M.js → cssMode-Cs_75Xhw.js} +1 -1
  313. package/studio/web/assets/{editor-DNcRHK54.js → editor-19b-Y1IN.js} +1 -1
  314. package/studio/web/assets/{html-Bdssedlg.js → html-DiYEQMpB.js} +1 -1
  315. package/studio/web/assets/{htmlMode-CoDlJ3fw.js → htmlMode-CmR0y7P_.js} +1 -1
  316. package/studio/web/assets/{index-D6sxmFLR.js → index-Dm0rfkJ7.js} +5 -5
  317. package/studio/web/assets/{index.lazy-tmU5BS8s.js → index.lazy-7vqt2CC3.js} +1 -1
  318. package/studio/web/assets/{javascript-B8meVSTH.js → javascript-BWtCFuOt.js} +1 -1
  319. package/studio/web/assets/{jsonMode-DpIPd35T.js → jsonMode-Buzzbv9y.js} +1 -1
  320. package/studio/web/assets/{languageServices-C_5FMJzQ.js → languageServices-SqsFWfTM.js} +1 -1
  321. package/studio/web/assets/{lspLanguageFeatures-BIzNBzPK.js → lspLanguageFeatures-EMV5cmjo.js} +1 -1
  322. package/studio/web/assets/{notifications-CvZivSbh.js → notifications-CAB-LZWT.js} +1 -1
  323. package/studio/web/assets/{notifications-CQf18QKb.js → notifications-DRzmSRxM.js} +1 -1
  324. package/studio/web/assets/{profile-DdOwtntb.js → profile-BNKAl79n.js} +1 -1
  325. package/studio/web/assets/{regions-n69fwagr.js → regions-CUow_Zw2.js} +1 -1
  326. package/studio/web/assets/{register-PfWTCXWB.js → register-Dkt3WUMp.js} +2 -2
  327. package/studio/web/assets/{setComponentFile-Bg6O7X0S.js → setComponentFile-BZRfMD0N.js} +1 -1
  328. package/studio/web/assets/{setup-CUx_aUDl.js → setup-D_yiEPO2.js} +2 -2
  329. package/studio/web/assets/{status-D7BVKqX9.js → status-DhHh1Ge-.js} +1 -1
  330. package/studio/web/assets/{toggleHighContrast-DBSyXzMr.js → toggleHighContrast-D7L1PDtV.js} +1 -1
  331. package/studio/web/assets/{tsMode-BByKCjBS.js → tsMode-CCwLk1YS.js} +1 -1
  332. package/studio/web/assets/{typescript-DDLnLpw9.js → typescript-BP1j1mjn.js} +1 -1
  333. package/studio/web/assets/{useEntityRestURL-31CHGaHk.js → useEntityRestURL-D7bnYxLw.js} +1 -1
  334. package/studio/web/assets/{workers-pR3jRY9D.js → workers-tOuCNT17.js} +1 -1
  335. package/studio/web/assets/{xml-2iRnMhQO.js → xml-BSG_3mQT.js} +1 -1
  336. package/studio/web/assets/{yaml-Bf92gJpd.js → yaml-DxiLprBB.js} +1 -1
  337. package/studio/web/index.html +1 -1
  338. package/utility/DESIGN.md +55 -0
  339. package/utility/errors/hdbError.ts +54 -0
  340. package/utility/hdbTerms.ts +2 -0
  341. package/utility/logging/harper_logger.ts +210 -30
  342. package/utility/logging/logGenerationCoordinator.ts +196 -0
  343. package/utility/logging/logRotation.ts +367 -0
  344. package/utility/logging/logRotator.ts +196 -91
  345. package/utility/npmUtilities.ts +6 -4
  346. package/utility/watcherFallback.ts +0 -122
  347. package/validation/configValidator.ts +6 -3
@@ -73,6 +73,8 @@ const packageUtils_js_1 = require("../../utility/packageUtils.js");
73
73
  const globals_js_1 = require("../../globals.js");
74
74
  const console_1 = require("console");
75
75
  const node_util_1 = require("node:util");
76
+ const logRotation_ts_1 = require("./logRotation.js");
77
+ const logGenerationCoordinator_ts_1 = require("./logGenerationCoordinator.js");
76
78
  const { isNativeError } = node_util_1.types;
77
79
  // store the native write function so we can call it after we write to the log file (and store it on process.stdout
78
80
  // because unit tests will create multiple instances of this module)
@@ -101,6 +103,17 @@ exports.OUTPUTS = {
101
103
  // Location of default config YAML.
102
104
  const DEFAULT_CONFIG_FILE = join(packageUtils_js_1.PACKAGE_ROOT, 'static', hdbTerms.HDB_DEFAULT_CONFIG_FILE);
103
105
  const CLOSE_LOG_FD_TIMEOUT = 10000;
106
+ // Above the module-scope initLogSettings() call below, which reaches getFileLogger: a const
107
+ // declared after it is still in its temporal dead zone when the file sink first reads one.
108
+ const LOG_TIME_USAGE_THRESHOLD = 100;
109
+ // How long to write straight to stdio after the log file refuses an append.
110
+ const APPEND_RETRY_COOLDOWN = 5000;
111
+ // Ceiling on how often a failing rotation may report itself; the failure repeats every check point.
112
+ const ROTATION_REPORT_INTERVAL = 60000;
113
+ const SET_ROTATION_POLICY = Symbol('setRotationPolicy');
114
+ const GET_ROTATION_POLICY = Symbol('getRotationPolicy');
115
+ const FILE_ROTATION_SOURCE = Symbol('fileRotationSource');
116
+ const SERVICE_NAME = worker_threads_1.workerData?.name?.replace(/ /g, '-') || 'main';
104
117
  let logConsole;
105
118
  let log_to_file;
106
119
  let logToStdstreams;
@@ -159,7 +172,24 @@ function updateLogger(logger, logOptions, name, mainLoggerRef = mainLogger) {
159
172
  // rotation entirely (#1877). Excluded when `logger` IS mainLoggerRef: the fallback would just
160
173
  // reassign mainLogger.rotation to itself, making it impossible to ever clear main's rotation.
161
174
  const inheritedRotation = logOptions.rotation ?? (logger === mainLoggerRef ? undefined : mainLoggerRef?.rotation);
162
- if (inheritedRotation && inheritedRotation === mainLoggerRef?.rotation) {
175
+ const loggerPolicy = logger[GET_ROTATION_POLICY]?.();
176
+ const mainPolicy = mainLoggerRef?.[GET_ROTATION_POLICY]?.();
177
+ const inheritsRotation = logOptions.rotation == null && logger !== mainLoggerRef;
178
+ const rotationSource = inheritsRotation ? mainPolicy?.source : loggerPolicy?.ownSource;
179
+ let path = logOptions.path;
180
+ if (path) {
181
+ if (!logOptions.root)
182
+ logOptions.root = pathModule.dirname(path);
183
+ }
184
+ else if (logOptions.root) {
185
+ path = join(logOptions.root, logName);
186
+ }
187
+ else {
188
+ path = mainLoggerRef.path;
189
+ if (!logOptions.root)
190
+ logOptions.root = pathModule.dirname(path);
191
+ }
192
+ if (inheritedRotation && inheritedRotation === mainLoggerRef?.rotation && path !== mainLoggerRef?.path) {
163
193
  // This logger has no rotation block of its own and is inheriting main's wholesale — but
164
194
  // inheriting `rotation.path` too would point this logger's archives at wherever main
165
195
  // archives to. If this logger's file lives on a different filesystem/volume than that
@@ -170,25 +200,18 @@ function updateLogger(logger, logOptions, name, mainLoggerRef = mainLogger) {
170
200
  // goes through `logOptions.rotation` above, not this fallback. Clone rather than mutate:
171
201
  // `inheritedRotation` is the literal object shared by mainLogger.rotation and every other
172
202
  // component that inherited it.
203
+ //
204
+ // Only when the paths differ. A logger writing to main's own file shares main's rotation
205
+ // state — file loggers are cached per path — so stripping there discards the operator's
206
+ // configured rotation.path for the main log itself, which no EXDEV risk justifies.
173
207
  const { path: _inheritedPath, ...rotationWithoutPath } = inheritedRotation;
174
- logger.rotation = rotationWithoutPath;
208
+ setRotationPolicy(rotationWithoutPath);
175
209
  }
176
210
  else {
177
- logger.rotation = inheritedRotation;
178
- }
179
- let path = logOptions.path;
180
- if (path) {
181
- if (!logOptions.root)
182
- logOptions.root = pathModule.dirname(path);
183
- }
184
- else if (logOptions.root) {
185
- path = join(logOptions.root, logName);
186
- }
187
- else {
188
- path = mainLoggerRef.path;
189
- if (!logOptions.root)
190
- logOptions.root = pathModule.dirname(path);
211
+ setRotationPolicy(inheritedRotation);
191
212
  }
213
+ // After the rotation above: assigning `path` goes through the setter that rebuilds this path's
214
+ // file logger, and it reads `logger.rotation` as it stands at that moment.
192
215
  if (path)
193
216
  logger.path = path;
194
217
  else
@@ -199,6 +222,12 @@ function updateLogger(logger, logOptions, name, mainLoggerRef = mainLogger) {
199
222
  // if there is a configured tag or if a component is logging to default/main log path, use the component name as the tag
200
223
  // to differentiate it
201
224
  logger.tag = logOptions.tag ?? ((mainLoggerRef.path === logger.path || exports.externalLogger.path === logger.path) && name);
225
+ function setRotationPolicy(rotation) {
226
+ if (logger[SET_ROTATION_POLICY])
227
+ logger[SET_ROTATION_POLICY](rotation, rotationSource, inheritsRotation);
228
+ else
229
+ logger.rotation = rotation;
230
+ }
202
231
  }
203
232
  // creates a logger where the methods are only defined if they are within the log level.
204
233
  // Using this conditional logger means that every method call must be optional like log.trace?.('message),
@@ -233,7 +262,19 @@ async function updateLogSettings() {
233
262
  // TODO: Any way to differentiate changes that we can and can't handle?
234
263
  rootConfig.on('change', updateLogSettings);
235
264
  }
236
- let rootConfigObject = rootConfig.config;
265
+ applyLogSettings(rootConfig.config);
266
+ }
267
+ // Separate from the watcher wiring above because the watcher it builds reads a process-wide path,
268
+ // which leaves no way to exercise these settings against a given config.
269
+ function applyLogSettings(rootConfigObject) {
270
+ // `ready` settles on every terminal read outcome, including ones that carry no config at all —
271
+ // see DESIGN.md, "Every terminal read outcome settles the barrier". Applying that as settings
272
+ // would not be "the defaults": `updateLogger` reads an absent `rotation` as rotation off and an
273
+ // absent `console` as console off, so an unreadable config would silently disable logging.
274
+ // What `initLogSettings()` established at startup stands until a real config arrives, which
275
+ // is why the watcher settles those outcomes with no config rather than an empty one.
276
+ if (!rootConfigObject || typeof rootConfigObject !== 'object')
277
+ return;
237
278
  const logOptions = rootConfigObject.logging ?? {};
238
279
  // Resolve relative paths against rootPath from the same config
239
280
  const rootPath = rootConfigObject.rootPath;
@@ -256,7 +297,9 @@ async function updateLogSettings() {
256
297
  for (const name in rootConfigObject) {
257
298
  // we now scan each component to see if it has logging individual configured
258
299
  const component = rootConfigObject[name];
259
- if (component.logging) {
300
+ // `myComponent:` with nothing under it parses to null, and an async listener's TypeError
301
+ // escapes the watcher's emit guard as an unhandled rejection.
302
+ if (component?.logging) {
260
303
  updateLogger(mainLogger.forComponent(name), component.logging, name);
261
304
  }
262
305
  else if (mainLogger.hasComponent(name)) {
@@ -456,6 +499,8 @@ module.exports = {
456
499
  // we can start using the RootConfigWatcher
457
500
  start: updateLogSettings,
458
501
  startOnMainThread: updateLogSettings,
502
+ // Test-only: applies a config without the process-wide watcher `updateLogSettings` builds.
503
+ _applyLogSettingsForTests: applyLogSettings,
459
504
  errorToString,
460
505
  errorForLog,
461
506
  inspectForLog,
@@ -516,6 +561,14 @@ function logsAtLevel(level) {
516
561
  function initLogSettings(forceInit = false) {
517
562
  try {
518
563
  if (hdbProperties === undefined || forceInit) {
564
+ if (forceInit && mainLogger?.[SET_ROTATION_POLICY]) {
565
+ const currentPath = mainLogger.path;
566
+ if (currentPath) {
567
+ const { ownSource } = mainLogger[GET_ROTATION_POLICY]();
568
+ mainLogger[SET_ROTATION_POLICY](undefined, ownSource, false);
569
+ mainLogger.path = currentPath;
570
+ }
571
+ }
519
572
  closeLogFile();
520
573
  const bootPropsFilePath = getPropsFilePath();
521
574
  let properties = (0, assignCmdEnvVariables_ts_1.default)(['ROOTPATH']);
@@ -692,14 +745,18 @@ function suppressLogging(callback) {
692
745
  loggingEnabled = true;
693
746
  }
694
747
  }
695
- const SERVICE_NAME = worker_threads_1.workerData?.name?.replace(/ /g, '-') || 'main';
696
748
  // these are used to store information about the current service and tag so we can prepend them to the log during
697
749
  // the writes, without having to pass the information through the Console instance
698
750
  let currentLevel = 'info'; // default is info
699
751
  let currentServiceName;
700
752
  let currentTag;
701
753
  function createLogger(options = {}) {
702
- let { path: logFilePath, level: logLevel, stdStreams: logToStdstreams, rotation, isExternalInstance, writeToLog, component, } = options;
754
+ let { path: logFilePath, level: logLevel, stdStreams: logToStdstreams, rotation, isExternalInstance, writeToLog, component, rotationSource, rotationInherited = false, } = options;
755
+ const ownRotationSource = Symbol('rotationPolicySource');
756
+ let currentRotationSource = rotationSource ?? ownRotationSource;
757
+ let previousRotationSource;
758
+ let currentRotationInherited = rotationInherited;
759
+ let rotationChangeIsAuthoritative = rotation !== undefined;
703
760
  if (!logLevel)
704
761
  logLevel = 'info';
705
762
  let level = typeof logLevel === 'number' ? logLevel : LOG_LEVEL_HIERARCHY[logLevel];
@@ -750,7 +807,8 @@ function createLogger(options = {}) {
750
807
  else if (logToStdstreams)
751
808
  process.stderr.write(log);
752
809
  }
753
- let logToFile = logFilePath && getFileLogger(logFilePath, rotation, isExternalInstance);
810
+ let logToFile = logFilePath && getFileLogger(logFilePath, rotation, isExternalInstance, rotationPolicy());
811
+ rotationPolicyApplied();
754
812
  function logPrepend(write) {
755
813
  return {
756
814
  write(log) {
@@ -772,6 +830,14 @@ function createLogger(options = {}) {
772
830
  stderr: logPrepend(writeToLog ?? logStdErr),
773
831
  colorMode: (logToStdstreams && colorMode) || false,
774
832
  }, level);
833
+ logger[SET_ROTATION_POLICY] = function (newRotation, source = ownRotationSource, inherited = false) {
834
+ previousRotationSource = currentRotationSource;
835
+ currentRotationSource = source ?? ownRotationSource;
836
+ currentRotationInherited = inherited;
837
+ rotationChangeIsAuthoritative = true;
838
+ logger.rotation = newRotation;
839
+ };
840
+ logger[GET_ROTATION_POLICY] = () => ({ ownSource: ownRotationSource, source: currentRotationSource });
775
841
  updateConditional(logger);
776
842
  logger.path = logFilePath;
777
843
  Object.defineProperty(logger, 'path', {
@@ -780,7 +846,11 @@ function createLogger(options = {}) {
780
846
  },
781
847
  set(path) {
782
848
  logFilePath = path;
783
- logToFile = getFileLogger(logFilePath, logger.rotation, isExternalInstance);
849
+ if (!logFilePath)
850
+ return;
851
+ logToFile = getFileLogger(logFilePath, logger.rotation, isExternalInstance, rotationPolicy());
852
+ logger.closeLogFile = logToFile.closeLogFile;
853
+ rotationPolicyApplied();
784
854
  if (isExternalInstance)
785
855
  writeToLogFile = logToFile;
786
856
  },
@@ -794,12 +864,15 @@ function createLogger(options = {}) {
794
864
  let componentLogger = components.get(name);
795
865
  if (!componentLogger) {
796
866
  const protoLogger = isExternal ? exports.externalLogger : logger;
867
+ const protoRotationPolicy = protoLogger[GET_ROTATION_POLICY]?.();
797
868
  componentLogger = createLogger({
798
869
  path: protoLogger.path,
799
870
  level: protoLogger.level,
800
871
  stdStreams: protoLogger.logToStdstreams,
801
872
  isExternalInstance: isExternal || name === 'external',
802
873
  rotation: protoLogger.rotation,
874
+ rotationSource: protoRotationPolicy?.source,
875
+ rotationInherited: true,
803
876
  writeToLog,
804
877
  component: true,
805
878
  });
@@ -816,35 +889,80 @@ function createLogger(options = {}) {
816
889
  logger.components = components;
817
890
  }
818
891
  return logger;
892
+ function rotationPolicy() {
893
+ return {
894
+ source: currentRotationSource,
895
+ previousSource: previousRotationSource,
896
+ inherited: currentRotationInherited,
897
+ authoritative: rotationChangeIsAuthoritative,
898
+ };
899
+ }
900
+ function rotationPolicyApplied() {
901
+ previousRotationSource = currentRotationSource;
902
+ rotationChangeIsAuthoritative = false;
903
+ }
819
904
  }
820
- const LOG_TIME_USAGE_THRESHOLD = 100;
821
- // How long to write straight to stdio after the log file refuses an append.
822
- const APPEND_RETRY_COOLDOWN = 5000;
823
905
  /**
824
906
  * Get the file logger for the given path. If it doesn't exist, create it.
825
907
  * @param path
826
908
  * @param isExternalInstance
827
909
  * @return {any}
828
910
  */
829
- function getFileLogger(path, rotation, isExternalInstance) {
911
+ function getFileLogger(path, rotation, isExternalInstance, rotationPolicy) {
830
912
  let logger = fileLoggers.get(path);
831
913
  let logFD, loggedFDError, loggedAppendError, logTimer, retryAppendAfter;
832
914
  let logBuffer;
915
+ let rotationProblemNotice;
833
916
  let logTimeUsage = 0;
917
+ let rotationGuard, logFDIdentity, nextRotationReport = 0;
834
918
  if (!logger) {
835
919
  logger = logToFile;
836
920
  logger.closeLogFile = closeLogFile;
921
+ // The guard has to be installed through the live closure: later calls for this path get the
922
+ // cached logger back, and their own logFD/logBuffer are dead.
923
+ logger.installRotationGuard = installRotationGuard;
837
924
  logger.path = path;
838
925
  fileLoggers.set(path, logger);
839
- }
840
- if (worker_threads_1.isMainThread && JSON.stringify(rotation) !== JSON.stringify(logger.rotation)) {
926
+ // Registered by the sink, not by the size guard: a thread that writes this file but has no
927
+ // guard (no maxSize, or rotation driven only by interval) still holds a descriptor, and an
928
+ // answer from it has to mean "released" rather than only "handler ran".
929
+ (0, logGenerationCoordinator_ts_1.registerLogSink)(path, { identity: () => logFDIdentity, close: closeLogFile });
930
+ }
931
+ const currentSource = logger[FILE_ROTATION_SOURCE];
932
+ const sameSource = currentSource === rotationPolicy.source;
933
+ const replacesPreviousSource = currentSource !== undefined && currentSource === rotationPolicy.previousSource;
934
+ const canInstall = rotation !== undefined &&
935
+ (!rotationPolicy.inherited || currentSource === undefined || sameSource || replacesPreviousSource);
936
+ const canClear = rotation === undefined && rotationPolicy.authoritative && (sameSource || replacesPreviousSource);
937
+ let reconfigured = false;
938
+ if (canInstall) {
939
+ logger[FILE_ROTATION_SOURCE] = rotationPolicy.source;
940
+ reconfigured = JSON.stringify(rotation) !== JSON.stringify(logger.rotation);
941
+ }
942
+ if (reconfigured) {
841
943
  logger.rotation = rotation;
944
+ // Every writing thread, and synchronously: request logging is produced by the HTTP workers, and
945
+ // at the rates that make maxSize matter a deferred guard misses megabytes before it exists.
946
+ logger.installRotationGuard(rotation);
947
+ }
948
+ else if (canClear) {
949
+ logger.rotation = undefined;
950
+ logger[FILE_ROTATION_SOURCE] = undefined;
951
+ logger.installRotationGuard(undefined);
952
+ reconfigured = true;
953
+ }
954
+ if (worker_threads_1.isMainThread && reconfigured) {
842
955
  setTimeout(() => {
843
- logger.rotator?.end();
844
- if (!rotation)
845
- return;
846
- const { logRotator } = require('./logRotator');
956
+ // Everything inside the try: a throw from a timer callback is unhandled, and neither
957
+ // require('./logRotator') (which reaches environmentManager's synchronous init) nor a
958
+ // rotator teardown may take the process down over log rotation (#847).
847
959
  try {
960
+ const previousRotator = logger.rotator;
961
+ logger.rotator = undefined;
962
+ previousRotator?.end();
963
+ if (!rotation)
964
+ return;
965
+ const { logRotator } = require('./logRotator');
848
966
  logger.rotator = logRotator({
849
967
  logger,
850
968
  ...rotation,
@@ -856,6 +974,50 @@ function getFileLogger(path, rotation, isExternalInstance) {
856
974
  }, 100);
857
975
  }
858
976
  return logger;
977
+ function installRotationGuard(newRotation) {
978
+ rotationGuard = undefined;
979
+ if (!newRotation || newRotation.enabled === false)
980
+ return;
981
+ const maxBytes = (0, logRotation_ts_1.parseMaxSize)(newRotation.maxSize);
982
+ if (!maxBytes) {
983
+ if (newRotation.maxSize != null)
984
+ reportRotationProblem(`logging.rotation.maxSize: ${logRotation_ts_1.INVALID_MAX_SIZE_MSG}`);
985
+ return;
986
+ }
987
+ try {
988
+ rotationGuard = (0, logRotation_ts_1.createRotationGuard)({
989
+ logPath: path,
990
+ maxBytes,
991
+ rotatedLogDir: (0, logRotation_ts_1.resolveRotatedLogDir)(path, newRotation.path),
992
+ // From the rotation block rather than environmentManager (which logRotator still reads):
993
+ // environmentManager imports this module, so it cannot be reached from the write path.
994
+ compress: newRotation.compress,
995
+ getLogIdentity: () => logFDIdentity,
996
+ closeLogFile,
997
+ report: reportRotationProblem,
998
+ onRotated(archivePath) {
999
+ // Same shape as every other line in the file: written straight to the sink, this
1000
+ // bypasses the prefix createLogger's logPrepend adds, and readLog parses by level.
1001
+ logToFile(`[${SERVICE_NAME}/${worker_threads_1.threadId}] [notify]: hdb.log rotated, old log moved to ${archivePath}`);
1002
+ },
1003
+ });
1004
+ }
1005
+ catch (error) {
1006
+ reportRotationProblem(`log rotation is disabled for ${path}: ${error}`);
1007
+ }
1008
+ }
1009
+ function reportRotationProblem(text) {
1010
+ // Straight to stdio, never back through this sink: the sink is what rotation is failing on.
1011
+ // Rate-limited rather than once-only, so a later, different failure is still reported.
1012
+ if (nextRotationReport > performance.now())
1013
+ return;
1014
+ nextRotationReport = performance.now() + ROTATION_REPORT_INTERVAL;
1015
+ const message = `Harper log rotation problem — ${text}`;
1016
+ // Scripted services discard stdio. Preserve the warning in the active file on the next
1017
+ // successful append as well, without recursing through the rotation guard.
1018
+ rotationProblemNotice = `${new Date().toISOString()} [${SERVICE_NAME}/${worker_threads_1.threadId}] [error]: ${message}\n`;
1019
+ writeToStdioDirectly(process.stderr, `${message}\n`);
1020
+ }
859
1021
  function logToFile(log) {
860
1022
  let entry = `${new Date().toISOString()} ${log}${log.endsWith('\n') ? '' : '\n'}`;
861
1023
  if (logBuffer) {
@@ -885,18 +1047,29 @@ function getFileLogger(path, rotation, isExternalInstance) {
885
1047
  }
886
1048
  // this is called on a timer, and will write the log buffer to the file
887
1049
  function logQueuedData(entry) {
888
- openLogFile(undefined);
889
1050
  const payload = logBuffer ? logBuffer.join('') : entry;
1051
+ // Released before anything can re-enter: the rotation notice is written from inside the append
1052
+ // below, and a re-entrant flush still holding this batch would write it twice.
1053
+ logBuffer = null;
1054
+ if (payload === undefined)
1055
+ return;
890
1056
  // A file that just refused a write will refuse the next one too, and every attempt costs a
891
1057
  // failed syscall plus a thrown error on whatever path is logging - which, on a full volume,
892
1058
  // is the request path at full rate. Go straight to stdio until the cooldown expires.
893
- if (logFD && !(retryAppendAfter > performance.now())) {
1059
+ // Opened after the guard: a guard recovering by rotation closes this descriptor first.
1060
+ const mayAppend = !(retryAppendAfter > performance.now()) && (rotationGuard?.beforeAppend() ?? true);
1061
+ openLogFile(undefined);
1062
+ if (logFD && mayAppend) {
894
1063
  let startTime = performance.now();
895
1064
  try {
896
- fs.appendFileSync(logFD, payload);
1065
+ const appendPayload = rotationProblemNotice ? rotationProblemNotice + payload : payload;
1066
+ const appendBuffer = Buffer.from(appendPayload);
1067
+ fs.appendFileSync(logFD, appendBuffer);
1068
+ rotationProblemNotice = undefined;
897
1069
  // Both cleared, so a volume that fills again months later reports itself again
898
1070
  retryAppendAfter = undefined;
899
1071
  loggedAppendError = false;
1072
+ rotationGuard?.recordWrite(appendBuffer.length);
900
1073
  }
901
1074
  catch (error) {
902
1075
  retryAppendAfter = performance.now() + APPEND_RETRY_COOLDOWN;
@@ -910,7 +1083,6 @@ function getFileLogger(path, rotation, isExternalInstance) {
910
1083
  writeToStdioDirectly(process.stderr, `Harper cannot write to its log file: ${error}\n`);
911
1084
  }
912
1085
  writeToStdioDirectly(process.stdout, payload);
913
- logBuffer = null;
914
1086
  return;
915
1087
  }
916
1088
  let endTime = performance.now();
@@ -920,8 +1092,6 @@ function getFileLogger(path, rotation, isExternalInstance) {
920
1092
  }
921
1093
  else
922
1094
  writeToStdioDirectly(process.stdout, payload);
923
- if (logBuffer)
924
- logBuffer = null;
925
1095
  }
926
1096
  function closeLogFile(_unused) {
927
1097
  try {
@@ -929,6 +1099,7 @@ function getFileLogger(path, rotation, isExternalInstance) {
929
1099
  }
930
1100
  catch { }
931
1101
  logFD = null;
1102
+ logFDIdentity = null;
932
1103
  if (isExternalInstance)
933
1104
  mainLogFd = null;
934
1105
  }
@@ -936,6 +1107,15 @@ function getFileLogger(path, rotation, isExternalInstance) {
936
1107
  if (!logFD) {
937
1108
  try {
938
1109
  logFD = fs.openSync(path, 'a');
1110
+ // Which generation this descriptor belongs to, recorded once here so the size guard's
1111
+ // checkpoint needs a single pathname stat to tell whether the file has moved under it.
1112
+ try {
1113
+ const opened = fs.fstatSync(logFD);
1114
+ logFDIdentity = { ino: opened.ino, dev: opened.dev };
1115
+ }
1116
+ catch {
1117
+ logFDIdentity = null;
1118
+ }
939
1119
  if (isExternalInstance)
940
1120
  mainLogFd = logFD;
941
1121
  }