@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
@@ -11,6 +11,8 @@ import {
11
11
  } from 'node:fs';
12
12
  import { join, basename, dirname, sep } from 'node:path';
13
13
  import { isMainThread } from 'node:worker_threads';
14
+
15
+ import { isDeployValidating } from '../server/serverHelpers/deployValidationState.ts';
14
16
  import { parseDocument } from 'yaml';
15
17
  import * as env from '../utility/environment/environmentManager.ts';
16
18
  import { PACKAGE_ROOT } from '../utility/packageUtils.js';
@@ -30,16 +32,23 @@ import { restartWorkers, getWorkerIndex } from '../server/threads/manageThreads.
30
32
  import { resetRestartNeeded, subscribeToRestartRequests } from './requestRestart.ts';
31
33
  import { trackScopeClose } from './scopeShutdown.ts';
32
34
  import { deployLifecycle } from './deployLifecycle.ts';
35
+ import { assertBranchedDatabases, assertIsolationConfig } from './Application.ts';
36
+ import { prepareBranches } from '../resources/branchDatabase.ts';
37
+ import {
38
+ isIsolatedApplication,
39
+ shouldLoadApplicationHere,
40
+ thisThreadOwnsApplication,
41
+ } from '../server/threads/isolatedApplications.ts';
33
42
  import { toScopeMount, nestScopeMount, type ScopeMount } from './scopeMount.ts';
34
43
  import { scopedImport } from '../security/jsLoader.ts';
35
44
  import { server } from '../server/Server.ts';
36
45
  import { Resources } from '../resources/Resources.ts';
37
- import { table } from '../resources/databases.ts';
46
+ import { scopedTableFactory } from '../resources/databases.ts';
38
47
  import { getHdbBasePath } from '../utility/environment/environmentManager.ts';
39
48
  import * as auth from '../security/auth.ts';
40
49
  import * as mqtt from '../server/mqtt.ts';
41
50
  import { getConfigObj, getConfigPath } from '../config/configUtils.ts';
42
- import { bootstrapModels } from '../resources/models/bootstrap.ts';
51
+ import { bootstrapModels, startModelsConfigHotReload } from '../resources/models/bootstrap.ts';
43
52
  import { ErrorResource } from '../resources/ErrorResource.ts';
44
53
  import { Scope } from './Scope.ts';
45
54
  import { ApplicationScope } from './ApplicationScope.ts';
@@ -47,17 +56,71 @@ import { ComponentV1, processResourceExtensionComponent } from './ComponentV1.ts
47
56
  import * as httpComponent from '../server/http.ts';
48
57
  import * as mcpComponent from './mcp/index.ts';
49
58
  import { Status } from '../server/status/index.ts';
50
- import { lifecycle as componentLifecycle } from './status/index.ts';
59
+ import { lifecycle as componentLifecycle, statusForComponent } from './status/index.ts';
51
60
  import { DEFAULT_CONFIG } from './DEFAULT_CONFIG.ts';
52
61
  import { materializeGlobalSecrets, processComponentEnv } from './componentSecrets.ts';
53
62
  import { PluginModule } from './PluginModule.ts';
54
- import { getEnvBuiltInComponents } from './Application.ts';
63
+ import {
64
+ getEnvBuiltInComponents,
65
+ recoverInterruptedActivations,
66
+ recoverInterruptedComponentExtraction,
67
+ recoverInterruptedComponentExtractions,
68
+ unsettleableComponentsFromDisk,
69
+ } from './Application.ts';
70
+ import { ComponentPreparationLockTimeoutError } from './componentPreparationLock.ts';
55
71
  import { pathToFileURL } from 'node:url';
56
72
 
57
73
  const CF_ROUTES_DIR = getConfigPath(CONFIG_PARAMS.COMPONENTSROOT);
74
+
58
75
  let loadedComponents = new Map<any, any>();
76
+
77
+ // Marks a registry entry as belonging to a deploy validation's throwaway load, so cleanup can tell whether
78
+ // an ordinary load has since ADOPTED that module. Checking "was it already loaded?" before the fact is not
79
+ // enough: ownership changes after that check when a real load reuses the entry while the validation is
80
+ // still running, and deleting it then removes a module a live consumer depends on.
81
+ const VALIDATION_OWNED = Symbol('validationOwnedModule');
59
82
  let watchesSetup;
60
83
  let resources;
84
+ const componentLoadTails = new Map<string, Promise<void>>();
85
+ type ComponentReadyPromises = WeakMap<object, Promise<void>>;
86
+
87
+ function serializeComponentLoad<T>(appName: string, load: () => Promise<T>): Promise<T> {
88
+ const previousLoad = componentLoadTails.get(appName);
89
+ const currentLoad = previousLoad ? previousLoad.then(load) : load();
90
+ const loadTail = currentLoad.then(
91
+ () => undefined,
92
+ () => undefined
93
+ );
94
+ componentLoadTails.set(appName, loadTail);
95
+ void loadTail.then(() => {
96
+ if (componentLoadTails.get(appName) === loadTail) componentLoadTails.delete(appName);
97
+ });
98
+ return currentLoad;
99
+ }
100
+
101
+ export async function readyComponentModules(
102
+ serverModules: Iterable<any>,
103
+ readyComponentPromises: ComponentReadyPromises = new WeakMap()
104
+ ): Promise<void> {
105
+ const readyPromises: Promise<void>[] = [];
106
+ for (const serverModule of serverModules) {
107
+ if (
108
+ (typeof serverModule !== 'object' && typeof serverModule !== 'function') ||
109
+ serverModule === null ||
110
+ typeof serverModule.ready !== 'function'
111
+ ) {
112
+ continue;
113
+ }
114
+ let readyPromise = readyComponentPromises.get(serverModule);
115
+ if (!readyPromise) {
116
+ readyPromise = Promise.resolve().then(() => serverModule.ready());
117
+ readyComponentPromises.set(serverModule, readyPromise);
118
+ void readyPromise.catch(() => readyComponentPromises.delete(serverModule));
119
+ }
120
+ readyPromises.push(readyPromise);
121
+ }
122
+ await Promise.all(readyPromises);
123
+ }
61
124
 
62
125
  /**
63
126
  * Load all the applications registered in Harper, those in the components directory as well as any directly
@@ -86,6 +149,49 @@ function rootConfigMount(appName: string): ScopeMount | undefined {
86
149
  return toScopeMount(getConfigObj()?.[appName]);
87
150
  }
88
151
 
152
+ /**
153
+ * The databases an operator declared that `appName` should get a private fork of, from the root
154
+ * config — the same place `host`/`urlPath` are declared, and for the same reason. Which databases an
155
+ * application forks is a deployment decision, not something the application checks in: the operator
156
+ * deploying it onto a cluster is who knows whether it should run against its own copy.
157
+ *
158
+ * ```yaml
159
+ * my-app:
160
+ * host: api.example.com
161
+ * branchedDatabases: [data]
162
+ * ```
163
+ */
164
+ function rootConfigBranchedDatabases(appName: string): string[] | true | undefined {
165
+ if (Object.hasOwn(TRUSTED_RESOURCE_PLUGINS, appName)) return undefined;
166
+ return (getConfigObj()?.[appName] as any)?.branchedDatabases;
167
+ }
168
+
169
+ /**
170
+ * Whether this thread is the one that loads `appName` (harper#642, tier 2). An isolated application
171
+ * is loaded by its dedicated worker and by nothing else; every other thread loads only the
172
+ * applications that are not isolated. Decided before any of the application's modules are imported.
173
+ * With no worker threads at all there is nowhere for an isolated application to run, so it fails
174
+ * closed here rather than silently sharing the only thread.
175
+ */
176
+ function placedOnThisThread(appName: string): boolean {
177
+ if (Object.hasOwn(TRUSTED_RESOURCE_PLUGINS, appName)) return true;
178
+ try {
179
+ assertIsolationConfig(appName, (getConfigObj()?.[appName] as any)?.isolated);
180
+ } catch (error) {
181
+ componentLifecycle.failed(appName, error, `Component '${appName}' failed to load`);
182
+ return false;
183
+ }
184
+ if (isIsolatedApplication(appName) && isMainThread && getWorkerIndex() === 0) {
185
+ componentLifecycle.failed(
186
+ appName,
187
+ new Error(`Application '${appName}' is isolated, which needs a worker thread of its own, but threads.count is 0`),
188
+ `Component '${appName}' failed to load`
189
+ );
190
+ return false;
191
+ }
192
+ return shouldLoadApplicationHere(appName);
193
+ }
194
+
89
195
  /**
90
196
  * Resolves the mount for `appName`, or reports the failure and returns `undefined` if the
91
197
  * configured `host`/`urlPath` is invalid. The caller must skip loading the application in that
@@ -110,15 +216,115 @@ function tryRootConfigMount(appName: string): { ok: true; mount: ScopeMount | un
110
216
  }
111
217
  }
112
218
 
113
- export async function loadComponentDirectories(loadedPluginModules?: Map<any, any>, loadedResources?: Resources) {
219
+ export async function loadComponentDirectories(
220
+ loadedPluginModules?: Map<any, any>,
221
+ loadedResources?: Resources,
222
+ readyComponentPromises: ComponentReadyPromises = new WeakMap(),
223
+ // Settled by boot BEFORE installApplications(), because that installs from the root config and would
224
+ // otherwise reinstall the previous release over an already-live candidate. `undefined` on a worker,
225
+ // which never runs that pass — distinct from an empty map, which would claim nothing is unreconciled.
226
+ interruptedActivationFailures?: Map<string, Error>
227
+ ) {
114
228
  if (loadedResources) resources = loadedResources;
115
229
  if (loadedPluginModules) loadedComponents = loadedPluginModules;
230
+ const cycleResources = resources;
231
+ const failedRecoveries = new Map<string, Error>(interruptedActivationFailures ?? []);
232
+ if (!interruptedActivationFailures) {
233
+ // No verdict from boot means this is a worker, which never runs the recovery pass. It reads the same
234
+ // evidence instead: a component whose activation could not be settled must not load here either,
235
+ // since workers are what actually serve it.
236
+ //
237
+ // Settlement itself runs here too, not just the read-only check. A worker can be auto-restarted at any
238
+ // time — including mid-activation — and the legacy pass below then has an unsettled journal in front
239
+ // of it, which it refuses to restore against: the component stalls instead of loading. Main-thread
240
+ // startup sequencing does not protect a worker that restarts later. Safe to run on any thread: each deployment is settled under
241
+ // the component preparation lock, which is cross-thread and cross-process, and the pass is idempotent.
242
+ try {
243
+ for (const [component, error] of await recoverInterruptedActivations(CF_ROUTES_DIR)) {
244
+ if (!failedRecoveries.has(component)) failedRecoveries.set(component, error);
245
+ }
246
+ } catch (error) {
247
+ harperLogger.warn(
248
+ 'Could not settle interrupted component activations on this thread:',
249
+ errorForLog(error instanceof Error ? error : new Error(String(error)))
250
+ );
251
+ }
252
+ // Plus anything a previous pass recorded as unsettleable, which settlement above leaves in place.
253
+ try {
254
+ for (const [component, error] of await unsettleableComponentsFromDisk(CF_ROUTES_DIR)) {
255
+ if (!failedRecoveries.has(component)) failedRecoveries.set(component, error);
256
+ }
257
+ } catch (error) {
258
+ harperLogger.warn(
259
+ 'Could not check for unsettled component activations:',
260
+ errorForLog(error instanceof Error ? error : new Error(String(error)))
261
+ );
262
+ }
263
+ }
264
+ try {
265
+ for (const [component, error] of await recoverInterruptedComponentExtractions(CF_ROUTES_DIR)) {
266
+ if (!failedRecoveries.has(component)) failedRecoveries.set(component, error);
267
+ }
268
+ } catch (error) {
269
+ const recoveryError = error instanceof Error ? error : new Error(String(error));
270
+ harperLogger.warn(
271
+ 'Loading existing filesystem components without deploy recovery because staging could not be inspected:',
272
+ errorForLog(recoveryError)
273
+ );
274
+ }
116
275
  // Materialize hdb_secret global-tier rows into process.env and snapshot the scoped tier before
117
276
  // any application loads (root components — including the Pro custody registration — have
118
277
  // already loaded by this point). Re-runs on each reload cycle, which is how changed/late-custody
119
278
  // secrets heal. Never throws.
120
279
  await materializeGlobalSecrets();
121
280
  const cfsLoaded: Promise<any>[] = [];
281
+ const deferredRecoveries = new Map(
282
+ [...failedRecoveries].filter(([, error]) => error instanceof ComponentPreparationLockTimeoutError)
283
+ );
284
+ const unreportedFailedRecoveries = new Map(
285
+ [...failedRecoveries].filter(([, error]) => !(error instanceof ComponentPreparationLockTimeoutError))
286
+ );
287
+ const deferComponentLoad = (appName: string) => {
288
+ const appFolder = join(CF_ROUTES_DIR, appName);
289
+ const appWasVisible = existsSync(appFolder);
290
+ if (appWasVisible) {
291
+ componentLifecycle.loading(appName, `Component '${appName}' is waiting for in-progress preparation to finish`);
292
+ }
293
+ void serializeComponentLoad(appName, () =>
294
+ recoverInterruptedComponentExtraction(CF_ROUTES_DIR, appName)
295
+ .then(async () => {
296
+ if (!existsSync(appFolder)) {
297
+ if (appWasVisible) {
298
+ statusForComponent(appName).unknown('Component directory no longer exists after preparation settled');
299
+ }
300
+ return;
301
+ }
302
+ if (!placedOnThisThread(appName)) return;
303
+ const mountResult = tryRootConfigMount(appName);
304
+ if (!mountResult.ok) return;
305
+ const loadedModules = new Set<any>();
306
+ await loadComponent(appFolder, cycleResources, HDB_ROOT_DIR_NAME, {
307
+ isRoot: false,
308
+ autoReload: false,
309
+ appName,
310
+ mount: mountResult.mount,
311
+ branchedDatabases: rootConfigBranchedDatabases(appName),
312
+ collectLoadedModules: loadedModules,
313
+ });
314
+ await readyComponentModules(loadedModules, readyComponentPromises);
315
+ })
316
+ .catch((error) => {
317
+ const recoveryError = error instanceof Error ? error : new Error(String(error));
318
+ if (appWasVisible) {
319
+ componentLifecycle.failed(
320
+ appName,
321
+ recoveryError,
322
+ `Component '${appName}' failed to load after waiting for in-progress preparation`
323
+ );
324
+ }
325
+ })
326
+ );
327
+ };
122
328
  if (existsSync(CF_ROUTES_DIR)) {
123
329
  const cfFolders = readdirSync(CF_ROUTES_DIR, { withFileTypes: true });
124
330
  for (const appEntry of cfFolders) {
@@ -127,35 +333,71 @@ export async function loadComponentDirectories(loadedPluginModules?: Map<any, an
127
333
  // Harper's own staging dirs (e.g. deploy aside copies) from loading as components.
128
334
  if (appEntry.name.startsWith('.')) continue;
129
335
  const appName = appEntry.name;
336
+ const recoveryError = failedRecoveries.get(appName);
337
+ if (recoveryError) {
338
+ if (recoveryError instanceof ComponentPreparationLockTimeoutError) {
339
+ deferredRecoveries.delete(appName);
340
+ deferComponentLoad(appName);
341
+ continue;
342
+ }
343
+ unreportedFailedRecoveries.delete(appName);
344
+ componentLifecycle.failed(
345
+ appName,
346
+ recoveryError,
347
+ `Component '${appName}' failed to load because its interrupted deployment could not be recovered`
348
+ );
349
+ continue;
350
+ }
351
+ if (!placedOnThisThread(appName)) continue;
130
352
  const appFolder = join(CF_ROUTES_DIR, appName);
131
353
  const mountResult = tryRootConfigMount(appName);
132
354
  if (!mountResult.ok) continue;
133
355
  cfsLoaded.push(
134
- loadComponent(appFolder, resources, HDB_ROOT_DIR_NAME, {
135
- isRoot: false,
136
- autoReload: false,
137
- appName,
138
- mount: mountResult.mount,
356
+ serializeComponentLoad(appName, () =>
357
+ loadComponent(appFolder, cycleResources, HDB_ROOT_DIR_NAME, {
358
+ isRoot: false,
359
+ autoReload: false,
360
+ appName,
361
+ mount: mountResult.mount,
362
+ branchedDatabases: rootConfigBranchedDatabases(appName),
363
+ })
364
+ ).catch((error) => {
365
+ const loadError = error instanceof Error ? error : new Error(String(error));
366
+ componentLifecycle.failed(appName, loadError, `Component '${appName}' failed to load`);
139
367
  })
140
368
  );
141
369
  }
142
370
  }
371
+ for (const [appName, recoveryError] of unreportedFailedRecoveries) {
372
+ componentLifecycle.failed(
373
+ appName,
374
+ recoveryError,
375
+ `Component '${appName}' failed to load because its interrupted deployment could not be recovered`
376
+ );
377
+ }
378
+ for (const appName of deferredRecoveries.keys()) deferComponentLoad(appName);
143
379
  const hdbAppFolder = process.env.RUN_HDB_APP;
144
380
  if (hdbAppFolder) {
145
381
  if (getWorkerIndex() === 0) harperLogger.info?.('Loading application from ' + hdbAppFolder);
146
382
  const mountResult = tryRootConfigMount(basename(hdbAppFolder));
147
- if (mountResult.ok) {
383
+ if (mountResult.ok && placedOnThisThread(basename(hdbAppFolder))) {
148
384
  cfsLoaded.push(
149
- loadComponent(hdbAppFolder, resources, hdbAppFolder, {
150
- isRoot: false,
151
- autoReload: Boolean(process.env.DEV_MODE),
152
- appName: hdbAppFolder,
153
- mount: mountResult.mount,
154
- })
385
+ serializeComponentLoad(hdbAppFolder, () =>
386
+ loadComponent(hdbAppFolder, cycleResources, hdbAppFolder, {
387
+ isRoot: false,
388
+ autoReload: Boolean(process.env.DEV_MODE),
389
+ // The directory arg above stays the absolute path -- that's a real filesystem
390
+ // location -- but `appName` here is the branch identity, and a branch path segment
391
+ // cannot contain `/`; use the same basename the config lookup on the next line uses.
392
+ appName: basename(hdbAppFolder),
393
+ mount: mountResult.mount,
394
+ branchedDatabases: rootConfigBranchedDatabases(basename(hdbAppFolder)),
395
+ })
396
+ )
155
397
  );
156
398
  }
157
399
  }
158
- return Promise.all(cfsLoaded).then(() => {
400
+ return await Promise.all(cfsLoaded).then(() => {
159
401
  watchesSetup = true;
160
402
  });
161
403
  }
@@ -233,6 +475,51 @@ export const loadedPaths = new Map();
233
475
  export const mainThreadInitialized = new Map<string, any>();
234
476
 
235
477
  let errorReporter;
478
+ /**
479
+ * Forget that a directory was loaded, so a throwaway load does not retain it forever. `loadedPaths` is
480
+ * keyed by realpath and never pruned, and every deploy validates a candidate under a fresh
481
+ * `.deploy-staging/<uuid>/` path — so without this the map grows by one dead entry per deploy for the life
482
+ * of the process.
483
+ */
484
+ export function forgetLoadedPath(componentDirectory: string): void {
485
+ let resolved: string | undefined;
486
+ try {
487
+ resolved = realpathSync(componentDirectory);
488
+ } catch {
489
+ // Already renamed live or discarded; fall through and prune by prefix anyway.
490
+ }
491
+ if (resolved) loadedPaths.delete(resolved);
492
+ // Nested `loadComponent()` calls register plugin and dependency realpaths UNDER the candidate, so
493
+ // deleting only the root leaves those behind — one dead entry per nested load, per deploy, forever.
494
+ const prefixes = [componentDirectory, resolved].filter(Boolean) as string[];
495
+ for (const key of loadedPaths.keys()) {
496
+ if (typeof key === 'string' && prefixes.some((prefix) => key === prefix || key.startsWith(prefix + sep))) {
497
+ loadedPaths.delete(key);
498
+ }
499
+ }
500
+ }
501
+
502
+ /**
503
+ * Release exactly the modules a throwaway validation load registered, as collected by that load's
504
+ * `collectLoadedModules` set.
505
+ *
506
+ * Exactly those, not a before/after diff of the global registry: validations are serialized with each other
507
+ * but not with ordinary loads, so a deferred real load for another component can register between the two
508
+ * snapshots — and a diff would then delete that live module.
509
+ */
510
+ export function forgetLoadedModules(modules: Iterable<any>): void {
511
+ // Only entries STILL owned by that validation. Validations serialize with each other but not with
512
+ // ordinary loads, so a real load can adopt a module the validation registered while it is still running —
513
+ // re-registering the same entry as live — and deleting it afterwards would take a live module with it.
514
+ for (const module of modules) {
515
+ if (loadedComponents.get(module) === VALIDATION_OWNED) loadedComponents.delete(module);
516
+ }
517
+ }
518
+
519
+ /** So a caller that installs a reporter can put the previous one back when it is done with it. */
520
+ export function getErrorReporter() {
521
+ return errorReporter;
522
+ }
236
523
  export function setErrorReporter(reporter) {
237
524
  errorReporter = reporter;
238
525
  }
@@ -252,22 +539,27 @@ export const getComponentName = () => compName;
252
539
  * every non-root component load and repaired if missing or pointing elsewhere.
253
540
  */
254
541
  function symlinkHarperModule(componentDirectory: string) {
255
- return new Promise<void>((resolve, reject) => {
542
+ return new Promise<void>((resolve) => {
256
543
  const store = Status.primaryStore;
257
- // Create timeout to avoid deadlocks
258
- const timeout = setTimeout(() => {
259
- store.unlock(componentDirectory);
260
- reject(new Error('symlinking harperdb module timed out'));
261
- }, 10_000);
262
-
263
- const callback = () => {
544
+ let timeout: NodeJS.Timeout;
545
+ const onUnlocked = () => {
264
546
  clearTimeout(timeout);
265
547
  resolve();
266
548
  };
267
- const lockAcquired = store.tryLock(componentDirectory, callback);
549
+ const lockAcquired = store.tryLock(componentDirectory, onUnlocked);
268
550
 
269
551
  if (!lockAcquired) {
270
- clearTimeout(timeout);
552
+ // The lock holder performs the fixup; wait for its unlock. The timer bounds the wait if
553
+ // the holder dies without unlocking, and must stay ref'd: the unlock wake arrives via an
554
+ // unref'd threadsafe function (see the invariant comment in threadServer.startServers).
555
+ // Timing out resolves rather than rejects: the fixup is idempotent maintenance, never
556
+ // worth failing the component load over.
557
+ timeout = setTimeout(() => {
558
+ harperLogger.warn(
559
+ `Timed out waiting for another thread to verify the harper module link in ${componentDirectory}; continuing with the link in its current state`
560
+ );
561
+ resolve();
562
+ }, 10_000);
271
563
  } else {
272
564
  try {
273
565
  // validate node_modules directory exists
@@ -311,6 +603,9 @@ function symlinkHarperModule(componentDirectory: string) {
311
603
  });
312
604
  }
313
605
 
606
+ // Direct access keeps lock timing deterministic without exposing a broader component-load seam.
607
+ export const _symlinkHarperModuleForTests = symlinkHarperModule;
608
+
314
609
  /**
315
610
  * This function handles the `handleApplication` call for a plugin in a sequential manner.
316
611
  * It ensures the execution of `handleApplication` happens on one thread at a time for a given scope.
@@ -421,11 +716,14 @@ export interface LoadComponentOptions {
421
716
  autoReload?: boolean;
422
717
  providedLoadedComponents?: Map<any, any>;
423
718
  appName?: string;
719
+ /** Databases this application forks, from its root-config entry (see `rootConfigBranchedDatabases`). */
720
+ branchedDatabases?: string[] | true;
424
721
  // When provided, every Scope created during this load is added to this set instead of being
425
722
  // auto-closed on worker shutdown. The caller then owns closing them. Used by transient loads
426
723
  // (e.g. the deploy pre-flight validation) so their deploy-lifecycle listeners don't accumulate
427
724
  // across deploys (#1462).
428
725
  collectScopes?: Set<Scope>;
726
+ collectLoadedModules?: Set<any>;
429
727
  // Routing the operator declared for this application in the root config (`host`/`urlPath` on
430
728
  // the application's entry). Applied to every plugin scope this load creates, and inherited by
431
729
  // components the application itself declares, so the whole subtree moves together.
@@ -457,6 +755,7 @@ export async function loadComponent(
457
755
  autoReload,
458
756
  appName,
459
757
  mount,
758
+ collectLoadedModules,
460
759
  } = options;
461
760
  applicationScope.runtimeRoot ??= resolvedFolder;
462
761
  applicationScope.allowedPath ??= realpathSync(componentDirectory);
@@ -477,6 +776,36 @@ export async function loadComponent(
477
776
  }
478
777
  applicationScope.config ??= config;
479
778
 
779
+ // Before any of the application's modules are imported: a branch has to exist by the time its
780
+ // code first reaches `databases`, and a declared branch that cannot be created must fail this
781
+ // application's load rather than let it run against the base it asked not to share.
782
+ // Declaring it in the application's own config.yaml is refused rather than ignored: it is a
783
+ // deployment decision and lives in the root config, and an application that believed it had a
784
+ // private fork while silently sharing the base is the one outcome this feature exists to stop.
785
+ if (!isRoot && config?.branchedDatabases !== undefined) {
786
+ const misplaced =
787
+ `Application '${options.appName ?? basename(componentDirectory)}' declares branchedDatabases in its own ` +
788
+ `config; it belongs in the root config entry for the application, alongside host and urlPath`;
789
+ // Logged as well as thrown: a component load that rejects this way surfaces downstream only as
790
+ // the application's routes and operations being absent, which says nothing about the cause.
791
+ harperLogger.error?.(misplaced);
792
+ throw new Error(misplaced);
793
+ }
794
+ // Only on the application's own load: nested components share its scope and its branches, and
795
+ // re-preparing per component would key a second branch off the same application name.
796
+ if (!isRoot && !options.applicationScope && options.branchedDatabases !== undefined) {
797
+ // The loader's own application identity, not the directory's basename: a branch path is
798
+ // keyed by this, and two components can share a basename (a nested one and a top-level one)
799
+ // while being different applications that must not share a fork each believes is private.
800
+ const branchAppName = options.appName ?? basename(componentDirectory);
801
+ assertBranchedDatabases(branchAppName, options.branchedDatabases);
802
+ applicationScope.branches = await prepareBranches(
803
+ branchAppName,
804
+ options.branchedDatabases,
805
+ applicationScope.mode
806
+ );
807
+ }
808
+
480
809
  // For non-root components with empty/null config (e.g., comment-only YAML),
481
810
  // don't synthesize DEFAULT_CONFIG. Empty config means the component has nothing
482
811
  // to load; falling back to DEFAULT_CONFIG would cause OptionsWatcher to wait
@@ -493,7 +822,10 @@ export async function loadComponent(
493
822
  // methods. Per-entry errors are logged and skipped by `bootstrapModels`.
494
823
  // Awaited so module-backed entries (#1471) finish importing before the
495
824
  // per-component iteration below; built-in entries register synchronously.
496
- if (isRoot) await bootstrapModels(config);
825
+ if (isRoot) {
826
+ await bootstrapModels(config);
827
+ startModelsConfigHotReload();
828
+ }
497
829
 
498
830
  // The `env:` block declares the component's environment expectations (string literal →
499
831
  // process.env; object → declaration satisfied from the hdb_secret store / process.env).
@@ -550,6 +882,9 @@ export async function loadComponent(
550
882
  if (!componentConfig) continue;
551
883
 
552
884
  // Initialize loading status for all components (applications and extensions)
885
+ // A root-config application (`package:`) is placed like a directory one: an isolated application
886
+ // loads only in its dedicated worker, and that worker loads no other application.
887
+ if (isRoot && componentConfig.package && !placedOnThisThread(componentName)) continue;
553
888
  componentLifecycle.loading(componentStatusName);
554
889
 
555
890
  const subApplicationScope = isRoot
@@ -601,6 +936,7 @@ export async function loadComponent(
601
936
  autoReload: false,
602
937
  appName: appName || componentName,
603
938
  collectScopes: options.collectScopes,
939
+ collectLoadedModules,
604
940
  // `host`/`urlPath` on this entry route the component being loaded. For an
605
941
  // application (no plugin module of its own) that entry is the only place an
606
942
  // operator can say where the app is served — its own config.yaml declares the
@@ -640,7 +976,10 @@ export async function loadComponent(
640
976
  // our own trusted modules can be directly retrieved from our map, otherwise use the (configurable) secure module loader
641
977
  const ensureTable = (options: any) => {
642
978
  options.origin = origin;
643
- return table(options);
979
+ return scopedTableFactory(
980
+ applicationScope.branches,
981
+ thisThreadOwnsApplication(applicationScope.name)
982
+ )(options);
644
983
  };
645
984
  // call the main start hook
646
985
  const network =
@@ -792,7 +1131,17 @@ export async function loadComponent(
792
1131
  resources,
793
1132
  ...componentConfig,
794
1133
  })) || extensionModule;
795
- loadedComponents.set(extensionModule, true);
1134
+ // `collectLoadedModules` serves two different purposes, so the two decisions below are made
1135
+ // separately. A deferred ORDINARY load passes one too, to await readiness — for that it has to
1136
+ // collect what it loaded whether or not the module was already registered. Only a VALIDATION
1137
+ // restricts its set, because there the set doubles as the cleanup list and a shared
1138
+ // `rest`/`graphql` module already live from a real load must not go on it.
1139
+ const validating = isDeployValidating();
1140
+ if (!validating || !loadedComponents.has(extensionModule)) collectLoadedModules?.add(extensionModule);
1141
+ // Ownership follows the validation CONTEXT, not the presence of a collect set. Keying it on the
1142
+ // set labelled a deferred ordinary load's registrations validation-owned, which would let the
1143
+ // next validation that collects that module delete a live one.
1144
+ loadedComponents.set(extensionModule, validating ? VALIDATION_OWNED : true);
796
1145
 
797
1146
  if (
798
1147
  (extensionModule.handleFile ||
@@ -850,7 +1199,7 @@ export async function loadComponent(
850
1199
  // — not abort the loop and discard a pending follow-up, like the save that fixes it.
851
1200
  try {
852
1201
  await loadComponentDirectories();
853
- await restartWorkers();
1202
+ await restartWorkers(undefined, undefined, true, null, '*');
854
1203
  } catch (error) {
855
1204
  harperLogger.error('Error during component reload', error);
856
1205
  }
@@ -23,6 +23,7 @@ export interface ComponentPreparationLockOwner {
23
23
  processInstanceId: string;
24
24
  token: string;
25
25
  ticket?: number;
26
+ purpose?: string;
26
27
  }
27
28
 
28
29
  export interface ComponentPreparationLockOptions {
@@ -30,8 +31,12 @@ export interface ComponentPreparationLockOptions {
30
31
  onWait?: (owner: ComponentPreparationLockOwner | null) => void;
31
32
  onReleaseError?: (error: unknown) => void;
32
33
  isOwnerAlive?: (owner: ComponentPreparationLockOwner) => boolean | Promise<boolean>;
34
+ purpose?: string;
35
+ renewTimeoutWhileOwnerAlive?: boolean | ((owner: ComponentPreparationLockOwner) => boolean | Promise<boolean>);
33
36
  }
34
37
 
38
+ export class ComponentPreparationLockTimeoutError extends Error {}
39
+
35
40
  export function componentPreparationLockIdentity(
36
41
  componentDirPath: string,
37
42
  platform: NodeJS.Platform = process.platform
@@ -244,10 +249,12 @@ async function acquireComponentPreparationLock(
244
249
  threadId,
245
250
  processInstanceId: COMPONENT_PREPARATION_PROCESS_INSTANCE_ID,
246
251
  token: randomUUID(),
252
+ purpose: options.purpose,
247
253
  };
248
254
  const choosingPath = join(lockRoot, `${lockName}.choosing.${owner.token}.json`);
249
255
  let ticketPath: string | undefined;
250
256
  const timeoutMs = options.timeoutMs ?? DEFAULT_LOCK_WAIT_TIMEOUT_MS;
257
+ const renewTimeoutWhileOwnerAlive = options.renewTimeoutWhileOwnerAlive ?? timeoutMs > 0;
251
258
  let deadline = performance.now() + timeoutMs;
252
259
 
253
260
  await mkdir(lockRoot, { recursive: true, mode: 0o700 });
@@ -264,7 +271,7 @@ async function acquireComponentPreparationLock(
264
271
  await rm(choosingPath, { force: true }).catch(() => {});
265
272
  }
266
273
 
267
- let waitingReported = false;
274
+ let waitingReportedForToken: string | undefined;
268
275
  try {
269
276
  for (;;) {
270
277
  const claims = await scanLiveClaims(lockRoot, lockName, options, owner.token);
@@ -276,17 +283,21 @@ async function acquireComponentPreparationLock(
276
283
  })[0];
277
284
  const blocker = claims.choosing[0] ?? precedingTicket;
278
285
  if (!blocker) break;
279
- if (!waitingReported) {
280
- waitingReported = true;
286
+ if (waitingReportedForToken !== blocker.token) {
287
+ waitingReportedForToken = blocker.token;
281
288
  options.onWait?.(blocker);
282
289
  }
283
290
  if (performance.now() >= deadline) {
284
- if (await ownerLivenessConfirmed(blocker, options)) {
291
+ const renewForOwner =
292
+ typeof renewTimeoutWhileOwnerAlive === 'function'
293
+ ? await renewTimeoutWhileOwnerAlive(blocker)
294
+ : renewTimeoutWhileOwnerAlive;
295
+ if (renewForOwner && (await ownerLivenessConfirmed(blocker, options))) {
285
296
  // A confirmed-live holder is allowed to finish; the deadline only bounds owners whose
286
297
  // liveness cannot be positively established.
287
298
  deadline = performance.now() + timeoutMs;
288
299
  } else {
289
- throw new Error(
300
+ throw new ComponentPreparationLockTimeoutError(
290
301
  `Timed out waiting for component preparation lock for ${canonicalPath}` +
291
302
  ` held by process ${blocker.pid}, thread ${blocker.threadId}`
292
303
  );
@@ -13,7 +13,10 @@ import type { ProgressEmitter } from '../server/serverHelpers/progressEmitter.ts
13
13
  const { HTTP_STATUS_CODES } = hdbErrors;
14
14
 
15
15
  const DEPLOYMENT_TABLE = terms.SYSTEM_TABLE_NAMES.DEPLOYMENT_TABLE_NAME;
16
- const TERMINAL_STATUSES = new Set(['success', 'failed', 'rolled_back']);
16
+ // `staged` belongs here: the build is complete on disk and nothing further happens to this deployment, so
17
+ // an SSE tail must finish and `delete_deployment_payload` must not refuse a tarball nobody is installing
18
+ // from any more. Activating the artifact is a separate deployment with a row of its own.
19
+ const TERMINAL_STATUSES = new Set(['success', 'failed', 'rolled_back', 'staged']);
17
20
 
18
21
  interface ListRequest {
19
22
  project?: string;