@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
@@ -38,7 +38,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.resolvePath = resolvePath;
40
40
  exports.getConfigPath = getConfigPath;
41
+ exports.isStorageExhausted = isStorageExhausted;
42
+ exports.persistConfigDuringBoot = persistConfigDuringBoot;
41
43
  exports.atomicWriteFile = atomicWriteFile;
44
+ exports.renameWithRetry = renameWithRetry;
42
45
  exports.createConfigFile = createConfigFile;
43
46
  exports.getDefaultConfig = getDefaultConfig;
44
47
  exports.getConfigValue = getConfigValue;
@@ -62,9 +65,11 @@ const hdbTerms = __importStar(require("../utility/hdbTerms.js"));
62
65
  const hdbUtils = __importStar(require("../utility/common_utils.js"));
63
66
  const harper_logger_ts_1 = __importDefault(require("../utility/logging/harper_logger.js"));
64
67
  const configValidator_ts_1 = require("../validation/configValidator.js");
68
+ const componentNames_ts_1 = require("../utility/componentNames.js");
65
69
  const fs_extra_1 = __importDefault(require("fs-extra"));
66
70
  const yaml_1 = __importDefault(require("yaml"));
67
71
  const path_1 = __importDefault(require("path"));
72
+ const node_os_1 = require("node:os");
68
73
  const node_worker_threads_1 = require("node:worker_threads");
69
74
  const node_crypto_1 = require("node:crypto");
70
75
  const is_number_1 = __importDefault(require("is-number"));
@@ -84,6 +89,7 @@ const packageUtils_js_1 = require("../utility/packageUtils.js");
84
89
  const env = __importStar(require("../utility/environment/environmentManager.js"));
85
90
  const harperConfigEnvVars_ts_1 = require("./harperConfigEnvVars.js");
86
91
  const componentEnvPrepass_ts_1 = require("./componentEnvPrepass.js");
92
+ const threadHeapMemory_ts_1 = require("../server/threads/threadHeapMemory.js");
87
93
  const { DATABASES_PARAM_CONFIG, CONFIG_PARAMS, CONFIG_PARAM_MAP } = hdbTerms;
88
94
  const UNINIT_GET_CONFIG_ERR = 'Unable to get config value because config is uninitialized';
89
95
  const CONFIG_INIT_MSG = 'Config successfully initialized';
@@ -140,56 +146,154 @@ function getConfigPath(param) {
140
146
  return value;
141
147
  return path_1.default.resolve(rootPath, value);
142
148
  }
143
- // Write atomically via temp file + rename so readers don't observe a truncated/empty file.
144
- // Temp path includes randomness so two worker threads in the same process (same pid) writing
145
- // in the same millisecond can't collide on the temp name and then race the rename.
146
- //
149
+ // Write atomically via a randomized temp file + rename so readers do not observe partial content
150
+ // and concurrent workers, which share process.pid, do not collide on a temp path.
147
151
  // Windows has no POSIX-style "replace an open file" semantics: rename() fails with
148
- // EPERM/EACCES if another thread/process has the destination momentarily open for read.
149
- // Every worker thread runs its own RootConfigWatcher (chokidar), so a write on one thread
150
- // routinely races a hot-reload read on another; Windows Defender / AV real-time scanning can
151
- // hold a similar transient handle. Retry with exponential backoff to ride out the race -
152
- // callers are synchronous, so the wait is a synchronous sleep rather than an async one.
153
- // The budget must outlast a single AV real-time scan pass (seconds, not hundreds of ms):
154
- // the previous ~910ms budget was exhausted twice in a row by the same test on a CI runner
155
- // (harper#2036), so the worst case is now ~3.6s.
156
- const RENAME_RETRY_MAX_ATTEMPTS = 12;
152
+ // EPERM/EACCES/EBUSY while another worker or AV holds the destination open. Root config watchers use
153
+ // readConfigFileSync so this blocking retry cannot wait on a read owned by its own worker.
154
+ // The budget is the wall-clock window of the 12-attempt schedule it replaced
155
+ // (10+20+40+80+160+320+500*6), so it stays a deadline rather than an attempt count without
156
+ // widening the stall: this loop blocks the calling worker's event loop, and `set_configuration`
157
+ // reaches it from a live request thread.
158
+ const RENAME_RETRY_BUDGET_MS = 3_630;
159
+ // Secondary guard only: stops a degenerate zero-delay option set from spinning the whole budget.
160
+ const RENAME_RETRY_MAX_ATTEMPTS = 25;
157
161
  const RENAME_RETRY_INITIAL_DELAY_MS = 10;
158
162
  const RENAME_RETRY_MAX_DELAY_MS = 500;
159
- // Never notified; exists only so Atomics.wait can time out (a synchronous, CPU-idle sleep).
163
+ // Never notified; Atomics.wait uses this only as a CPU-idle synchronous sleep.
160
164
  const renameRetrySleepBuffer = new Int32Array(new SharedArrayBuffer(4));
161
- function atomicWriteFile(filePath, content, { maxRetries = RENAME_RETRY_MAX_ATTEMPTS, initialDelayMs = RENAME_RETRY_INITIAL_DELAY_MS, maxDelayMs = RENAME_RETRY_MAX_DELAY_MS, } = {}) {
165
+ // Classified by code alone rather than gated to win32 like the read side: `process.platform` does
166
+ // not answer whether this filesystem can replace an open file — WSL drvfs, CIFS/SMB and Docker
167
+ // Desktop bind mounts all report `linux` and return these codes transiently.
168
+ function isRetryableRenameError(code) {
169
+ return code === 'EPERM' || code === 'EACCES' || code === 'EBUSY';
170
+ }
171
+ function validateRenameRetryOptions({ retryBudgetMs, maxRetries, initialDelayMs, maxDelayMs }) {
172
+ const invalidOption = !Number.isFinite(retryBudgetMs) ||
173
+ retryBudgetMs < 0 ||
174
+ (!Number.isFinite(maxRetries) && maxRetries !== Infinity) ||
175
+ maxRetries < 0 ||
176
+ !Number.isFinite(initialDelayMs) ||
177
+ initialDelayMs < 0 ||
178
+ !Number.isFinite(maxDelayMs) ||
179
+ maxDelayMs < 0;
180
+ if (invalidOption) {
181
+ throw new RangeError('rename retry options must be non-negative numbers');
182
+ }
183
+ }
184
+ // Linux has no libuv mapping for EDQUOT, so a quota-exhausted write surfaces as
185
+ // `Unknown system error -122` with an unusable `code`; the numeric errno is the portable signal
186
+ // (EDQUOT is 122 on Linux, 69 on macOS).
187
+ const STORAGE_EXHAUSTED_CODES = new Set(['ENOSPC', 'EDQUOT']);
188
+ // EDQUOT is absent from os.constants.errno on platforms without quotas, so filter before negating:
189
+ // -undefined is NaN, which would sit in the set matching nothing and reading as a bug.
190
+ const STORAGE_EXHAUSTED_ERRNOS = new Set([node_os_1.constants.errno.ENOSPC, node_os_1.constants.errno.EDQUOT].filter((errno) => errno !== undefined).map((errno) => -errno));
191
+ function isStorageExhausted(error) {
192
+ return STORAGE_EXHAUSTED_CODES.has(error?.code) || STORAGE_EXHAUSTED_ERRNOS.has(error?.errno);
193
+ }
194
+ // Boot-path persistence of derived config is best-effort: on an exhausted volume a fatal write here
195
+ // is an un-breakable restart loop, because freeing space needs a started process (#847).
196
+ function persistConfigDuringBoot(artifactPath, write) {
197
+ try {
198
+ write();
199
+ return true;
200
+ }
201
+ catch (error) {
202
+ if (!isStorageExhausted(error))
203
+ throw error;
204
+ harper_logger_ts_1.default.error(`Storage exhausted (${error.code ?? error.errno}) writing ${artifactPath}; continuing startup with the in-memory configuration. The file on disk is unchanged - free space on the Harper volume to restore config persistence.`);
205
+ return false;
206
+ }
207
+ }
208
+ // Returns true when the file was written, false when an unchanged write was skipped.
209
+ function atomicWriteFile(filePath, content, { retryBudgetMs = RENAME_RETRY_BUDGET_MS, maxRetries = RENAME_RETRY_MAX_ATTEMPTS, initialDelayMs = RENAME_RETRY_INITIAL_DELAY_MS, maxDelayMs = RENAME_RETRY_MAX_DELAY_MS, skipIfUnchanged = false, } = {}) {
210
+ // Before the temp write, so an option set that can never rename leaves no file behind.
211
+ validateRenameRetryOptions({ retryBudgetMs, maxRetries, initialDelayMs, maxDelayMs });
212
+ // Opt-in: skipping means no mtime bump, so no watcher event. Only callers that re-derive the
213
+ // same file every boot want that.
214
+ if (skipIfUnchanged && matchesFileContent(filePath, content))
215
+ return false;
162
216
  const tempPath = `${filePath}.${process.pid}.${node_worker_threads_1.threadId}.${(0, node_crypto_1.randomBytes)(4).toString('hex')}.tmp`;
163
- fs_extra_1.default.writeFileSync(tempPath, content);
217
+ try {
218
+ fs_extra_1.default.writeFileSync(tempPath, content);
219
+ }
220
+ catch (err) {
221
+ // The open succeeds before the write runs out of room, leaving the temp file behind.
222
+ removeTempFile(tempPath);
223
+ throw err;
224
+ }
225
+ try {
226
+ renameWithRetry(tempPath, filePath, { retryBudgetMs, maxRetries, initialDelayMs, maxDelayMs });
227
+ }
228
+ catch (err) {
229
+ // The temp name carries fresh randomness on every call, so a spent budget would otherwise
230
+ // leave a file nothing else will ever collect.
231
+ removeTempFile(tempPath);
232
+ throw err;
233
+ }
234
+ return true;
235
+ }
236
+ function renameWithRetry(fromPath, toPath, { retryBudgetMs = RENAME_RETRY_BUDGET_MS, maxRetries = RENAME_RETRY_MAX_ATTEMPTS, initialDelayMs = RENAME_RETRY_INITIAL_DELAY_MS, maxDelayMs = RENAME_RETRY_MAX_DELAY_MS, } = {}) {
237
+ validateRenameRetryOptions({ retryBudgetMs, maxRetries, initialDelayMs, maxDelayMs });
164
238
  let retries = maxRetries;
165
239
  let delayMs = initialDelayMs;
240
+ let retryDeadline;
241
+ let finalAttempt = false;
242
+ let attempts = 0;
243
+ const startedAt = performance.now();
166
244
  while (true) {
167
245
  try {
168
- fs_extra_1.default.renameSync(tempPath, filePath);
169
- break;
246
+ attempts++;
247
+ fs_extra_1.default.renameSync(fromPath, toPath);
248
+ return;
170
249
  }
171
250
  catch (err) {
172
- if (retries > 0 && (err.code === 'EPERM' || err.code === 'EACCES')) {
251
+ if (!finalAttempt && retries > 0 && isRetryableRenameError(err.code)) {
173
252
  retries--;
174
- // Sleep synchronously (all call sites are sync) to allow the holder to close the
175
- // file. Atomics.wait yields the thread to the OS instead of spinning the CPU,
176
- // which is what makes a multi-second worst-case budget affordable.
177
- if (delayMs > 0)
178
- Atomics.wait(renameRetrySleepBuffer, 0, 0, delayMs);
179
- delayMs = Math.min(delayMs * 2, maxDelayMs);
180
- continue;
181
- }
182
- // if it fails we should clean up the tmp file
183
- try {
184
- fs_extra_1.default.unlinkSync(tempPath);
253
+ if (retryDeadline === undefined) {
254
+ retryDeadline = performance.now() + retryBudgetMs;
255
+ }
256
+ const remainingBudgetMs = retryDeadline - performance.now();
257
+ if (remainingBudgetMs > 0) {
258
+ // Sleep synchronously (all call sites are sync) to allow the holder to close the
259
+ // file. Atomics.wait yields the thread to the OS instead of spinning the CPU,
260
+ // which is what makes a multi-second worst-case budget affordable.
261
+ const sleepMs = Math.min(delayMs, remainingBudgetMs);
262
+ finalAttempt = sleepMs === remainingBudgetMs;
263
+ if (sleepMs > 0)
264
+ Atomics.wait(renameRetrySleepBuffer, 0, 0, sleepMs);
265
+ delayMs = Math.min(Math.max(delayMs * 2, RENAME_RETRY_INITIAL_DELAY_MS), maxDelayMs);
266
+ continue;
267
+ }
185
268
  }
186
- catch {
187
- // ignore cleanup errors
269
+ // Whether the budget was spent or the code was never retryable is the difference
270
+ // between a holder that never released and a one-off failure, and neither survives on
271
+ // the rethrown error.
272
+ if (isRetryableRenameError(err.code)) {
273
+ harper_logger_ts_1.default.warn(`Could not replace ${toPath}: ${err.code} after ${attempts} attempts over ${Math.round(performance.now() - startedAt)}ms`);
188
274
  }
189
275
  throw err;
190
276
  }
191
277
  }
192
278
  }
279
+ function removeTempFile(tempPath) {
280
+ try {
281
+ fs_extra_1.default.unlinkSync(tempPath);
282
+ }
283
+ catch {
284
+ // ignore cleanup errors
285
+ }
286
+ }
287
+ function matchesFileContent(filePath, content) {
288
+ if (typeof content !== 'string')
289
+ return false;
290
+ try {
291
+ return fs_extra_1.default.readFileSync(filePath, 'utf8') === content;
292
+ }
293
+ catch {
294
+ return false;
295
+ }
296
+ }
193
297
  /**
194
298
  * Builds the Harper config file using user inputs and default values from defaultConfig.yaml
195
299
  * @param args - any args that the user provided.
@@ -200,7 +304,7 @@ function createConfigFile(args, skipFsValidation = false) {
200
304
  // Loop through the user inputted args. Match them to a parameter in the default config file and update value.
201
305
  let schemasArgs;
202
306
  for (const arg in args) {
203
- let configParam = CONFIG_PARAM_MAP[arg.toLowerCase()];
307
+ let configParam = lookupConfigParam(arg);
204
308
  // Schemas config args are handled differently, so if they exist set them to var that will be used by setSchemasConfig
205
309
  if (configParam === CONFIG_PARAMS.DATABASES) {
206
310
  if (Array.isArray(args[arg])) {
@@ -213,7 +317,7 @@ function createConfigFile(args, skipFsValidation = false) {
213
317
  }
214
318
  continue;
215
319
  }
216
- if (!configParam && (arg.endsWith('_package') || arg.endsWith('_port'))) {
320
+ if (!configParam && isSuffixEscapedParam(arg)) {
217
321
  configParam = arg;
218
322
  }
219
323
  if (configParam !== undefined) {
@@ -306,7 +410,7 @@ function getDefaultConfig(param) {
306
410
  const configDoc = parseYamlDoc(DEFAULT_CONFIG_FILE_PATH);
307
411
  flatDefaultConfigObj = flattenConfig(configDoc.toJSON());
308
412
  }
309
- const paramMap = CONFIG_PARAM_MAP[param.toLowerCase()];
413
+ const paramMap = lookupConfigParam(param);
310
414
  if (paramMap === undefined)
311
415
  return undefined;
312
416
  return flatDefaultConfigObj[paramMap.toLowerCase()];
@@ -327,7 +431,7 @@ function getConfigValue(param) {
327
431
  harper_logger_ts_1.default.trace(UNINIT_GET_CONFIG_ERR);
328
432
  return undefined;
329
433
  }
330
- const paramMap = CONFIG_PARAM_MAP[param.toLowerCase()];
434
+ const paramMap = lookupConfigParam(param);
331
435
  if (paramMap === undefined)
332
436
  return undefined;
333
437
  return flatConfigObj[paramMap.toLowerCase()];
@@ -377,7 +481,11 @@ function ensureConfigKeysPresent(keys) {
377
481
  }
378
482
  if (added.length === 0)
379
483
  return [];
380
- atomicWriteFile(configFilePath, String(configDoc));
484
+ // Worker threads re-read the config from disk and never run this backfill, so a key that only
485
+ // exists in this thread's memory activates nowhere that serves requests: report nothing when the
486
+ // write was refused rather than logging an activation the request path did not get.
487
+ if (!persistConfigDuringBoot(configFilePath, () => atomicWriteFile(configFilePath, String(configDoc))))
488
+ return [];
381
489
  // Mirror the additions into the already-memoized config so a built-in gated on the new key
382
490
  // activates on the CURRENT boot: componentLoader reads the root config from getConfigObj(),
383
491
  // which is cached early in boot — before an upgrade backfill runs — so a file-only write would
@@ -566,7 +674,7 @@ function checkForUpdatedConfig(configDoc, configFilePath) {
566
674
  if (configDoc.errors?.length > 0) {
567
675
  throw (0, hdbError_ts_1.handleHDBError)(new Error(), `Error parsing harperdb-config.yaml ${configDoc.errors}`, commonErrors_ts_1.HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR);
568
676
  }
569
- atomicWriteFile(configFilePath, String(configDoc));
677
+ persistConfigDuringBoot(configFilePath, () => atomicWriteFile(configFilePath, String(configDoc)));
570
678
  }
571
679
  }
572
680
  /**
@@ -636,6 +744,8 @@ function validateConfig(configDoc, skipFsValidation = false) {
636
744
  const domainSocketWarning = (0, configValidator_ts_1.getDomainSocketPathLengthWarning)(validation.value.rootPath, domainSocket);
637
745
  if (domainSocketWarning)
638
746
  harper_logger_ts_1.default.warn(domainSocketWarning);
747
+ if ((0, configValidator_ts_1.isLegacySqlApplicationEntry)(configJson.sql))
748
+ harper_logger_ts_1.default.warn("The root config entry 'sql' is an application, but 'sql' now configures Harper's SQL engine. Redeploy that application under a different name and remove the 'sql' entry; until then the SQL engine settings cannot be configured.");
639
749
  }
640
750
  /**
641
751
  * Updates the in memory flattened config object. Does not update the config file.
@@ -648,7 +758,7 @@ function updateConfigObject(param, value) {
648
758
  // This is here to allow unit tests to work when HDB is not installed.
649
759
  flatConfigObj = {};
650
760
  }
651
- const configObjKey = CONFIG_PARAM_MAP[param.toLowerCase()];
761
+ const configObjKey = lookupConfigParam(param);
652
762
  if (configObjKey === undefined) {
653
763
  harper_logger_ts_1.default.trace(`Unable to update config object because config param '${param}' does not exist`);
654
764
  return;
@@ -691,6 +801,69 @@ function updateConfigObject(param, value) {
691
801
  node[leaf] = value;
692
802
  }
693
803
  }
804
+ /**
805
+ * Canonical config param for an arg name, or `undefined` when the name is not a config param.
806
+ * `Object.hasOwn` because a bare lookup resolves inherited names: `constructor` yields an
807
+ * `Object.prototype` member that then fails `.split('_')` or `.toLowerCase()`.
808
+ */
809
+ function lookupConfigParam(arg) {
810
+ if (typeof arg !== 'string')
811
+ return undefined;
812
+ const name = arg.toLowerCase();
813
+ return Object.hasOwn(CONFIG_PARAM_MAP, name) ? CONFIG_PARAM_MAP[name] : undefined;
814
+ }
815
+ const COMPONENT_PARAM_SUFFIXES = ['_package', '_port'];
816
+ function suffixEscapedComponentName(arg) {
817
+ if (typeof arg !== 'string')
818
+ return undefined;
819
+ const suffix = COMPONENT_PARAM_SUFFIXES.find((candidate) => arg.endsWith(candidate));
820
+ if (suffix === undefined)
821
+ return undefined;
822
+ const component = arg.slice(0, -suffix.length);
823
+ return component === '' ? undefined : component;
824
+ }
825
+ /**
826
+ * Component entries (`my-component_package`, `my-component_port`) are operator-named, so they
827
+ * cannot be enumerated in CONFIG_PARAM_MAP and bypass it. This escape is the one way to write a
828
+ * root component entry without going through deploy_component, so a reserved name is excluded.
829
+ */
830
+ function isSuffixEscapedParam(arg) {
831
+ const component = suffixEscapedComponentName(arg);
832
+ return component !== undefined && !(0, componentNames_ts_1.isReservedComponentName)(component);
833
+ }
834
+ function findReservedComponentParams(args) {
835
+ const reserved = [];
836
+ for (const arg in args) {
837
+ if (!Object.hasOwn(args, arg))
838
+ continue;
839
+ const component = suffixEscapedComponentName(arg);
840
+ if (component !== undefined && (0, componentNames_ts_1.isReservedComponentName)(component))
841
+ reserved.push(arg);
842
+ }
843
+ return reserved;
844
+ }
845
+ const MAX_REPORTED_UNRECOGNIZED = 10;
846
+ /**
847
+ * Render unrecognized names for an error that also reaches the operations log: control characters
848
+ * are stripped so a name containing a newline cannot forge a log line, and the list is capped so a
849
+ * body carrying thousands of unknown keys cannot produce an unbounded message.
850
+ */
851
+ function describeUnrecognized(names) {
852
+ const shown = names
853
+ .slice(0, MAX_REPORTED_UNRECOGNIZED)
854
+ // eslint-disable-next-line no-control-regex
855
+ .map((name) => name.replace(/[\u0000-\u001f\u007f]/g, '?'));
856
+ const remaining = names.length - shown.length;
857
+ return remaining > 0 ? `${shown.join(', ')} (and ${remaining} more)` : shown.join(', ');
858
+ }
859
+ function findUnrecognizedParams(args) {
860
+ let unrecognized;
861
+ for (const arg in args) {
862
+ if (lookupConfigParam(arg) === undefined && !isSuffixEscapedParam(arg))
863
+ (unrecognized ??= []).push(arg);
864
+ }
865
+ return unrecognized ?? [];
866
+ }
694
867
  /**
695
868
  * Updates and validates a config value in config file. Can also create a backup of config before updating.
696
869
  * @param param - the config value to update
@@ -741,7 +914,7 @@ function updateConfigValue(param, value, parsedArgs = undefined, createBackup =
741
914
  configParam = param;
742
915
  }
743
916
  else {
744
- configParam = CONFIG_PARAM_MAP[param.toLowerCase()];
917
+ configParam = lookupConfigParam(param);
745
918
  if (configParam === undefined) {
746
919
  throw (0, hdbError_ts_1.handleHDBError)(new Error(), `Unable to update config, unrecognized config parameter: ${param}`, commonErrors_ts_1.HTTP_STATUS_CODES.BAD_REQUEST, undefined, undefined, true);
747
920
  }
@@ -753,7 +926,7 @@ function updateConfigValue(param, value, parsedArgs = undefined, createBackup =
753
926
  else {
754
927
  // Loop through the user inputted args. Match them to a parameter in the default config file and update value.
755
928
  for (const arg in parsedArgs) {
756
- let configParam = CONFIG_PARAM_MAP[arg.toLowerCase()];
929
+ let configParam = lookupConfigParam(arg);
757
930
  // If setting http.securePort to the same value as http.port, set http.port to null to avoid clashing ports
758
931
  if (configParam === CONFIG_PARAMS.HTTP_SECUREPORT &&
759
932
  parsedArgs[arg] === flatConfigObj[CONFIG_PARAMS.HTTP_PORT]?.toString()) {
@@ -777,7 +950,7 @@ function updateConfigValue(param, value, parsedArgs = undefined, createBackup =
777
950
  configDoc.setIn(['threads', 'count'], threadCount);
778
951
  }
779
952
  }
780
- if (!configParam && (arg.endsWith('_package') || arg.endsWith('_port'))) {
953
+ if (!configParam && isSuffixEscapedParam(arg)) {
781
954
  configParam = arg;
782
955
  }
783
956
  if (configParam !== undefined) {
@@ -947,14 +1120,49 @@ function getConfiguration() {
947
1120
  const configDoc = parseYamlDoc(configFilePath);
948
1121
  return configDoc.toJSON();
949
1122
  }
1123
+ // `set_configuration` is the one config writer that also fans out (`replicated: true`), so a value
1124
+ // accepted here lands on every peer at once and the next rolling restart takes the whole cluster
1125
+ // down together (harper-pro#558). Boot-time writers are deliberately not gated the same way: config
1126
+ // that already exists has to stay bootable, so it is recovered at the point of use instead
1127
+ // (server/threads/threadHeapMemory.ts).
1128
+ function assertThreadHeapMemoryStartable(configFields) {
1129
+ for (const field in configFields) {
1130
+ const configParam = CONFIG_PARAM_MAP[field.toLowerCase()];
1131
+ let configured;
1132
+ if (configParam === CONFIG_PARAMS.THREADS_MAXHEAPMEMORY)
1133
+ configured = configFields[field];
1134
+ else if (configParam === CONFIG_PARAMS.THREADS)
1135
+ configured = readSectionHeapMemory(configFields[field]);
1136
+ else
1137
+ continue;
1138
+ const value = castConfigValue(CONFIG_PARAMS.THREADS_MAXHEAPMEMORY, configured);
1139
+ if (typeof value !== 'number' || (0, threadHeapMemory_ts_1.isStartableThreadHeapMemory)(value))
1140
+ continue;
1141
+ throw (0, hdbError_ts_1.handleHDBError)(new Error(), commonErrors_ts_1.HDB_ERROR_MSGS.CONFIG_VALIDATION(`'threads.maxHeapMemory' must be greater than or equal to ${hdbTerms.MIN_THREAD_HEAP_MEMORY_MB}`), commonErrors_ts_1.HTTP_STATUS_CODES.BAD_REQUEST, undefined, undefined, true);
1142
+ }
1143
+ }
1144
+ // A whole `threads` section reaches the same config key, and `threads` canonicalizes to itself
1145
+ // rather than to `threads_count`. It arrives either as an object or as the JSON string
1146
+ // castConfigValue parses, and flattenConfig lowercases every key on the way back out, so the nested
1147
+ // name has to be matched the same way the top-level one is.
1148
+ function readSectionHeapMemory(section) {
1149
+ const parsed = castConfigValue(CONFIG_PARAMS.THREADS, section);
1150
+ if (!hdbUtils.isObject(parsed))
1151
+ return undefined;
1152
+ for (const key in parsed)
1153
+ if (key.toLowerCase() === 'maxheapmemory')
1154
+ return parsed[key];
1155
+ }
950
1156
  /**
951
1157
  * Set Configuration - this function sets new configuration
952
1158
  * @param setConfigJson
953
1159
 
954
1160
  */
955
1161
  async function setConfiguration(setConfigJson) {
1162
+ // `hdb_auth_header` is the 4.x spelling of `hdbAuthHeader`, and `impersonate` is a generic
1163
+ // operation-body field (server/operationsServer.ts): control fields, never config params.
956
1164
  // eslint-disable-next-line no-unused-vars
957
- const { operation, hdb_user, hdbAuthHeader, replicated, ...configFields } = setConfigJson;
1165
+ const { operation, hdb_user, hdbAuthHeader, hdb_auth_header, impersonate, replicated, ...configFields } = setConfigJson;
958
1166
  // Operation-control field, not a config param: enforce boolean (matching other
959
1167
  // `replicated` surfaces, e.g. analyticsValidator) before any local write so a
960
1168
  // malformed value like the string "false" — which is truthy — can't apply config
@@ -962,6 +1170,18 @@ async function setConfiguration(setConfigJson) {
962
1170
  if (replicated !== undefined && typeof replicated !== 'boolean') {
963
1171
  throw (0, hdbError_ts_1.handleHDBError)(new Error(), `'replicated' must be a boolean`, commonErrors_ts_1.HTTP_STATUS_CODES.BAD_REQUEST, undefined, undefined, true);
964
1172
  }
1173
+ const reservedComponentParams = findReservedComponentParams(configFields);
1174
+ if (reservedComponentParams.length > 0) {
1175
+ throw (0, hdbError_ts_1.handleHDBError)(new Error(), `Unable to update config, cannot configure a component whose name is reserved for Harper's own configuration section: ${describeUnrecognized(reservedComponentParams)}`, commonErrors_ts_1.HTTP_STATUS_CODES.BAD_REQUEST, undefined, undefined, true);
1176
+ }
1177
+ // Before any local write: the writer skips names it cannot resolve, so a request mixing
1178
+ // recognized and unrecognized names would otherwise apply the recognized half and still report
1179
+ // success.
1180
+ const unrecognized = findUnrecognizedParams(configFields);
1181
+ if (unrecognized.length > 0) {
1182
+ throw (0, hdbError_ts_1.handleHDBError)(new Error(), `Unable to update config, unrecognized config parameter${unrecognized.length > 1 ? 's' : ''}: ${describeUnrecognized(unrecognized)}`, commonErrors_ts_1.HTTP_STATUS_CODES.BAD_REQUEST, undefined, undefined, true);
1183
+ }
1184
+ assertThreadHeapMemoryStartable(configFields);
965
1185
  try {
966
1186
  updateConfigValue(undefined, undefined, configFields, true);
967
1187
  if (replicated) {
@@ -1043,9 +1263,16 @@ function applyRuntimeEnvVarConfig(configDoc, configFilePath, options = {}) {
1043
1263
  return;
1044
1264
  // Convert to JSON for processing
1045
1265
  const configObj = configDoc.toJSON();
1266
+ let saveEnvConfigState;
1267
+ let confirmEnvConfigState;
1268
+ let commitEnvConfigState;
1046
1269
  try {
1047
1270
  // Apply env vars with source tracking and drift detection
1048
- (0, harperConfigEnvVars_ts_1.applyRuntimeEnvConfig)(configObj, rootPath, options);
1271
+ ({
1272
+ saveState: saveEnvConfigState,
1273
+ confirmConfigWritten: confirmEnvConfigState,
1274
+ commitState: commitEnvConfigState,
1275
+ } = (0, harperConfigEnvVars_ts_1.prepareRuntimeEnvConfig)(configObj, rootPath, options));
1049
1276
  // If securePort was set to the same value as port, auto-null port to avoid clashing
1050
1277
  if (configObj.http?.port && configObj.http?.port === configObj.http?.securePort) {
1051
1278
  configObj.http.port = null;
@@ -1067,17 +1294,47 @@ function applyRuntimeEnvVarConfig(configDoc, configFilePath, options = {}) {
1067
1294
  harper_logger_ts_1.default.error(`Failed to apply runtime env config: ${error.message}`);
1068
1295
  throw error;
1069
1296
  }
1070
- // We're done here if no config file to write to
1297
+ // Install has no config file yet and no process to keep alive, so its snapshot write stays
1298
+ // mandatory - an install that never recorded originals should fail, not proceed.
1071
1299
  if (!configFilePath) {
1300
+ commitEnvConfigState();
1072
1301
  return;
1073
1302
  }
1303
+ // Every worker thread runs initConfig and derives the same merged config, so letting them all
1304
+ // persist it means N threads racing over one pair of files for a result they already agree on.
1305
+ // The main thread owns the on-disk copy; a worker runs on the in-memory one.
1306
+ if (!node_worker_threads_1.isMainThread)
1307
+ return;
1074
1308
  // Persist changes to file
1075
1309
  try {
1076
1310
  if (configDoc.errors?.length > 0) {
1077
1311
  throw (0, hdbError_ts_1.handleHDBError)(new Error(), `Error parsing harperdb-config.yaml: ${configDoc.errors}`, commonErrors_ts_1.HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR);
1078
1312
  }
1079
- atomicWriteFile(configFilePath, String(configDoc));
1080
- harper_logger_ts_1.default.debug('Config file updated with runtime env var values');
1313
+ // Stage, write the file, promote by rename: the confirmed state is the only record of the
1314
+ // file's pre-env values, so no write an exhausted volume can refuse may stand between it and
1315
+ // disk. See DESIGN.md, boot-path config persistence.
1316
+ let stateStaged = false;
1317
+ if (persistConfigDuringBoot(`${rootPath} env config state`, () => (stateStaged = saveEnvConfigState()))) {
1318
+ let configPersisted = false;
1319
+ let configRewritten = false;
1320
+ try {
1321
+ configPersisted = persistConfigDuringBoot(configFilePath, () => {
1322
+ configRewritten = atomicWriteFile(configFilePath, String(configDoc), { skipIfUnchanged: true });
1323
+ });
1324
+ }
1325
+ finally {
1326
+ if (!configPersisted && stateStaged)
1327
+ (0, harperConfigEnvVars_ts_1.discardConfigState)(rootPath);
1328
+ }
1329
+ if (configPersisted) {
1330
+ if (stateStaged)
1331
+ confirmEnvConfigState();
1332
+ // Distinguished, because this is the line that answers "did something rewrite my config?"
1333
+ harper_logger_ts_1.default.debug(configRewritten
1334
+ ? 'Config file updated with runtime env var values'
1335
+ : 'Config file already matched the runtime env var values');
1336
+ }
1337
+ }
1081
1338
  }
1082
1339
  catch (error) {
1083
1340
  harper_logger_ts_1.default.error(`Failed to write config file after applying runtime env vars: ${error.message}`);