@harperfast/harper 5.3.0-alpha.1 → 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 (291) hide show
  1. package/bin/cliOperations.ts +12 -0
  2. package/bin/restart.ts +66 -6
  3. package/components/Application.ts +1134 -112
  4. package/components/OptionsWatcher.ts +368 -102
  5. package/components/Scope.ts +20 -1
  6. package/components/componentLoader.ts +43 -4
  7. package/components/deploymentOperations.ts +4 -1
  8. package/components/deploymentRecorder.ts +9 -2
  9. package/components/operations.js +284 -52
  10. package/components/operationsValidation.js +49 -2
  11. package/components/packageComponent.ts +25 -1
  12. package/components/requestRestart.ts +11 -0
  13. package/config/RootConfigWatcher.ts +191 -37
  14. package/config/configReadRetry.ts +62 -0
  15. package/config/configUtils.ts +78 -26
  16. package/config/parseConfigFile.ts +34 -0
  17. package/config/readConfigFileSync.ts +44 -0
  18. package/config/watcherArming.ts +59 -0
  19. package/config-root.schema.json +4 -0
  20. package/dataLayer/harperBridge/ResourceBridge.ts +28 -2
  21. package/dist/bin/cliOperations.js +13 -0
  22. package/dist/bin/cliOperations.js.map +1 -1
  23. package/dist/bin/restart.js +42 -6
  24. package/dist/bin/restart.js.map +1 -1
  25. package/dist/components/Application.d.ts +104 -9
  26. package/dist/components/Application.js +954 -102
  27. package/dist/components/Application.js.map +1 -1
  28. package/dist/components/OptionsWatcher.d.ts +4 -1
  29. package/dist/components/OptionsWatcher.js +378 -104
  30. package/dist/components/OptionsWatcher.js.map +1 -1
  31. package/dist/components/Scope.js +15 -1
  32. package/dist/components/Scope.js.map +1 -1
  33. package/dist/components/componentLoader.js +35 -3
  34. package/dist/components/componentLoader.js.map +1 -1
  35. package/dist/components/deploymentOperations.js +4 -1
  36. package/dist/components/deploymentOperations.js.map +1 -1
  37. package/dist/components/deploymentRecorder.d.ts +4 -2
  38. package/dist/components/deploymentRecorder.js +1 -0
  39. package/dist/components/deploymentRecorder.js.map +1 -1
  40. package/dist/components/operations.d.ts +28 -0
  41. package/dist/components/operations.js +263 -54
  42. package/dist/components/operations.js.map +1 -1
  43. package/dist/components/operationsValidation.js +48 -2
  44. package/dist/components/operationsValidation.js.map +1 -1
  45. package/dist/components/packageComponent.js +24 -0
  46. package/dist/components/packageComponent.js.map +1 -1
  47. package/dist/components/requestRestart.d.ts +1 -0
  48. package/dist/components/requestRestart.js +7 -0
  49. package/dist/components/requestRestart.js.map +1 -1
  50. package/dist/config/RootConfigWatcher.d.ts +2 -0
  51. package/dist/config/RootConfigWatcher.js +189 -35
  52. package/dist/config/RootConfigWatcher.js.map +1 -1
  53. package/dist/config/configReadRetry.d.ts +8 -0
  54. package/dist/config/configReadRetry.js +62 -0
  55. package/dist/config/configReadRetry.js.map +1 -0
  56. package/dist/config/configUtils.d.ts +10 -9
  57. package/dist/config/configUtils.js +63 -27
  58. package/dist/config/configUtils.js.map +1 -1
  59. package/dist/config/parseConfigFile.d.ts +4 -0
  60. package/dist/config/parseConfigFile.js +35 -0
  61. package/dist/config/parseConfigFile.js.map +1 -0
  62. package/dist/config/readConfigFileSync.d.ts +1 -0
  63. package/dist/config/readConfigFileSync.js +47 -0
  64. package/dist/config/readConfigFileSync.js.map +1 -0
  65. package/dist/config/watcherArming.d.ts +15 -0
  66. package/dist/config/watcherArming.js +59 -0
  67. package/dist/config/watcherArming.js.map +1 -0
  68. package/dist/dataLayer/harperBridge/ResourceBridge.js +21 -2
  69. package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
  70. package/dist/index.d.ts +1 -0
  71. package/dist/index.js +4 -1
  72. package/dist/index.js.map +1 -1
  73. package/dist/json/systemSchema.json +3 -0
  74. package/dist/resources/DatabaseTransaction.d.ts +25 -0
  75. package/dist/resources/DatabaseTransaction.js +224 -18
  76. package/dist/resources/DatabaseTransaction.js.map +1 -1
  77. package/dist/resources/LMDBTransaction.d.ts +2 -1
  78. package/dist/resources/LMDBTransaction.js +22 -3
  79. package/dist/resources/LMDBTransaction.js.map +1 -1
  80. package/dist/resources/PrimaryRocksDatabase.js +22 -6
  81. package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
  82. package/dist/resources/RecordEncoder.d.ts +1 -1
  83. package/dist/resources/RecordEncoder.js +21 -5
  84. package/dist/resources/RecordEncoder.js.map +1 -1
  85. package/dist/resources/Resource.js +97 -13
  86. package/dist/resources/Resource.js.map +1 -1
  87. package/dist/resources/ResourceInterface.d.ts +8 -0
  88. package/dist/resources/RocksIndexStore.js +2 -1
  89. package/dist/resources/RocksIndexStore.js.map +1 -1
  90. package/dist/resources/RocksTransactionLogStore.d.ts +10 -0
  91. package/dist/resources/RocksTransactionLogStore.js +104 -33
  92. package/dist/resources/RocksTransactionLogStore.js.map +1 -1
  93. package/dist/resources/Table.d.ts +58 -7
  94. package/dist/resources/Table.js +1095 -346
  95. package/dist/resources/Table.js.map +1 -1
  96. package/dist/resources/analytics/write.js +10 -3
  97. package/dist/resources/analytics/write.js.map +1 -1
  98. package/dist/resources/auditStore.d.ts +170 -0
  99. package/dist/resources/auditStore.js +457 -11
  100. package/dist/resources/auditStore.js.map +1 -1
  101. package/dist/resources/dataLoader.js +3 -4
  102. package/dist/resources/dataLoader.js.map +1 -1
  103. package/dist/resources/databases.d.ts +16 -13
  104. package/dist/resources/databases.js +624 -176
  105. package/dist/resources/databases.js.map +1 -1
  106. package/dist/resources/derivedIndexRegistry.d.ts +5 -0
  107. package/dist/resources/derivedIndexRegistry.js +68 -0
  108. package/dist/resources/derivedIndexRegistry.js.map +1 -0
  109. package/dist/resources/derivedIndexRuntime.d.ts +215 -0
  110. package/dist/resources/derivedIndexRuntime.js +2027 -0
  111. package/dist/resources/derivedIndexRuntime.js.map +1 -0
  112. package/dist/resources/graphql.js +3 -2
  113. package/dist/resources/graphql.js.map +1 -1
  114. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +102 -9
  115. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +848 -39
  116. package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
  117. package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
  118. package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
  119. package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
  120. package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
  121. package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
  122. package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
  123. package/dist/resources/nodeIdMapping.d.ts +5 -0
  124. package/dist/resources/nodeIdMapping.js +49 -0
  125. package/dist/resources/nodeIdMapping.js.map +1 -1
  126. package/dist/resources/recordLock.d.ts +47 -4
  127. package/dist/resources/recordLock.js +138 -7
  128. package/dist/resources/recordLock.js.map +1 -1
  129. package/dist/resources/recordLockCoordinator.d.ts +557 -0
  130. package/dist/resources/recordLockCoordinator.js +2565 -0
  131. package/dist/resources/recordLockCoordinator.js.map +1 -0
  132. package/dist/resources/replayLogs.js +5 -0
  133. package/dist/resources/replayLogs.js.map +1 -1
  134. package/dist/resources/replicatedApplyFailure.d.ts +16 -0
  135. package/dist/resources/replicatedApplyFailure.js +63 -0
  136. package/dist/resources/replicatedApplyFailure.js.map +1 -0
  137. package/dist/resources/scheduler/scheduler.js +3 -3
  138. package/dist/resources/scheduler/scheduler.js.map +1 -1
  139. package/dist/resources/search.d.ts +10 -4
  140. package/dist/resources/search.js +160 -40
  141. package/dist/resources/search.js.map +1 -1
  142. package/dist/resources/tracked.d.ts +5 -1
  143. package/dist/resources/tracked.js +74 -23
  144. package/dist/resources/tracked.js.map +1 -1
  145. package/dist/security/jsLoader.js +6 -4
  146. package/dist/security/jsLoader.js.map +1 -1
  147. package/dist/server/REST.js +33 -2
  148. package/dist/server/REST.js.map +1 -1
  149. package/dist/server/http.d.ts +5 -1
  150. package/dist/server/http.js +34 -2
  151. package/dist/server/http.js.map +1 -1
  152. package/dist/server/serverHelpers/Headers.d.ts +2 -0
  153. package/dist/server/serverHelpers/Headers.js +6 -0
  154. package/dist/server/serverHelpers/Headers.js.map +1 -1
  155. package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
  156. package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
  157. package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
  158. package/dist/server/serverHelpers/Request.d.ts +5 -10
  159. package/dist/server/serverHelpers/Request.js +38 -136
  160. package/dist/server/serverHelpers/Request.js.map +1 -1
  161. package/dist/server/serverHelpers/contentTypes.d.ts +2 -0
  162. package/dist/server/serverHelpers/contentTypes.js +189 -15
  163. package/dist/server/serverHelpers/contentTypes.js.map +1 -1
  164. package/dist/server/serverHelpers/serverUtilities.js +96 -17
  165. package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
  166. package/dist/server/storageReclamation.js +1 -1
  167. package/dist/server/storageReclamation.js.map +1 -1
  168. package/dist/server/threads/isolatedApplications.d.ts +47 -0
  169. package/dist/server/threads/isolatedApplications.js +171 -0
  170. package/dist/server/threads/isolatedApplications.js.map +1 -0
  171. package/dist/server/threads/logRotationTransport.d.ts +1 -0
  172. package/dist/server/threads/logRotationTransport.js +33 -0
  173. package/dist/server/threads/logRotationTransport.js.map +1 -0
  174. package/dist/server/threads/manageThreads.d.ts +64 -6
  175. package/dist/server/threads/manageThreads.js +261 -12
  176. package/dist/server/threads/manageThreads.js.map +1 -1
  177. package/dist/server/threads/socketRouter.d.ts +1 -0
  178. package/dist/server/threads/socketRouter.js +196 -13
  179. package/dist/server/threads/socketRouter.js.map +1 -1
  180. package/dist/server/threads/threadServer.js +30 -7
  181. package/dist/server/threads/threadServer.js.map +1 -1
  182. package/dist/utility/errors/hdbError.d.ts +24 -0
  183. package/dist/utility/errors/hdbError.js +58 -1
  184. package/dist/utility/errors/hdbError.js.map +1 -1
  185. package/dist/utility/hdbTerms.d.ts +2 -0
  186. package/dist/utility/hdbTerms.js +2 -0
  187. package/dist/utility/hdbTerms.js.map +1 -1
  188. package/dist/utility/logging/harper_logger.js +217 -38
  189. package/dist/utility/logging/harper_logger.js.map +1 -1
  190. package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
  191. package/dist/utility/logging/logGenerationCoordinator.js +184 -0
  192. package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
  193. package/dist/utility/logging/logRotation.d.ts +46 -0
  194. package/dist/utility/logging/logRotation.js +365 -0
  195. package/dist/utility/logging/logRotation.js.map +1 -0
  196. package/dist/utility/logging/logRotator.d.ts +1 -1
  197. package/dist/utility/logging/logRotator.js +172 -92
  198. package/dist/utility/logging/logRotator.js.map +1 -1
  199. package/dist/utility/npmUtilities.js +6 -4
  200. package/dist/utility/npmUtilities.js.map +1 -1
  201. package/dist/utility/watcherFallback.d.ts +0 -45
  202. package/dist/utility/watcherFallback.js +1 -125
  203. package/dist/utility/watcherFallback.js.map +1 -1
  204. package/dist/validation/configValidator.js +6 -3
  205. package/dist/validation/configValidator.js.map +1 -1
  206. package/index.ts +6 -0
  207. package/json/systemSchema.json +3 -0
  208. package/npm-shrinkwrap.json +131 -41
  209. package/package.json +10 -3
  210. package/resources/DESIGN.md +124 -19
  211. package/resources/DatabaseTransaction.ts +230 -17
  212. package/resources/LMDBTransaction.ts +21 -3
  213. package/resources/PrimaryRocksDatabase.ts +20 -7
  214. package/resources/RecordEncoder.ts +25 -5
  215. package/resources/Resource.ts +97 -13
  216. package/resources/ResourceInterface.ts +8 -0
  217. package/resources/RocksIndexStore.ts +2 -1
  218. package/resources/RocksTransactionLogStore.ts +111 -31
  219. package/resources/Table.ts +1224 -393
  220. package/resources/analytics/write.ts +10 -3
  221. package/resources/auditStore.ts +460 -11
  222. package/resources/dataLoader.ts +3 -4
  223. package/resources/databases.ts +610 -146
  224. package/resources/derivedIndexRegistry.ts +56 -0
  225. package/resources/derivedIndexRuntime.ts +2292 -0
  226. package/resources/graphql.ts +3 -2
  227. package/resources/indexes/HierarchicalNavigableSmallWorld.ts +905 -46
  228. package/resources/indexes/hnswDerivedIndex.ts +531 -0
  229. package/resources/indexes/hnswPlaneBinding.ts +174 -0
  230. package/resources/nodeIdMapping.ts +50 -0
  231. package/resources/recordLock.ts +173 -7
  232. package/resources/recordLockCoordinator.ts +3043 -0
  233. package/resources/replayLogs.ts +5 -0
  234. package/resources/replicatedApplyFailure.ts +77 -0
  235. package/resources/scheduler/scheduler.ts +4 -4
  236. package/resources/search.ts +169 -49
  237. package/resources/tracked.ts +73 -22
  238. package/security/jsLoader.ts +6 -4
  239. package/server/DESIGN.md +11 -0
  240. package/server/REST.ts +36 -3
  241. package/server/http.ts +34 -2
  242. package/server/serverHelpers/Headers.ts +5 -1
  243. package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
  244. package/server/serverHelpers/Request.ts +33 -131
  245. package/server/serverHelpers/contentTypes.ts +188 -15
  246. package/server/serverHelpers/serverUtilities.ts +143 -24
  247. package/server/storageReclamation.ts +2 -2
  248. package/server/threads/isolatedApplications.ts +157 -0
  249. package/server/threads/logRotationTransport.ts +40 -0
  250. package/server/threads/manageThreads.js +254 -12
  251. package/server/threads/socketRouter.ts +217 -11
  252. package/server/threads/threadServer.js +30 -7
  253. package/studio/web/assets/{Chat-BnCBegQz.js → Chat-D3j-1yY1.js} +1 -1
  254. package/studio/web/assets/{FloatingChat-CoDW1ySS.js → FloatingChat-BxJGYcfB.js} +3 -3
  255. package/studio/web/assets/{apiToken-Bwk5BLXW.js → apiToken-CT55oWOe.js} +1 -1
  256. package/studio/web/assets/{applications-DHxGi7JH.js → applications-D9Ct9_vm.js} +1 -1
  257. package/studio/web/assets/{cssMode-s0cWI-_M.js → cssMode-DV8H7VwA.js} +1 -1
  258. package/studio/web/assets/{editor-DNcRHK54.js → editor-uatc0unt.js} +1 -1
  259. package/studio/web/assets/{html-Bdssedlg.js → html-Bm6D6paN.js} +1 -1
  260. package/studio/web/assets/{htmlMode-CoDlJ3fw.js → htmlMode-CEn7tpLG.js} +1 -1
  261. package/studio/web/assets/{index-D6sxmFLR.js → index-BIXW6Pu4.js} +5 -5
  262. package/studio/web/assets/{index.lazy-tmU5BS8s.js → index.lazy-UI7L-Vrk.js} +1 -1
  263. package/studio/web/assets/{javascript-B8meVSTH.js → javascript-CJ0G3AFZ.js} +1 -1
  264. package/studio/web/assets/{jsonMode-DpIPd35T.js → jsonMode-DQADAYEa.js} +1 -1
  265. package/studio/web/assets/{languageServices-C_5FMJzQ.js → languageServices-CAQJXWcI.js} +1 -1
  266. package/studio/web/assets/{lspLanguageFeatures-BIzNBzPK.js → lspLanguageFeatures-CCQ8P5sY.js} +1 -1
  267. package/studio/web/assets/{notifications-CQf18QKb.js → notifications-BbxTU6Aw.js} +1 -1
  268. package/studio/web/assets/{notifications-CvZivSbh.js → notifications-Cvb3P1lB.js} +1 -1
  269. package/studio/web/assets/{profile-DdOwtntb.js → profile-Yyb7gsvL.js} +1 -1
  270. package/studio/web/assets/{regions-n69fwagr.js → regions-OgjGHlU5.js} +1 -1
  271. package/studio/web/assets/{register-PfWTCXWB.js → register-6qwNEOY3.js} +2 -2
  272. package/studio/web/assets/{setComponentFile-Bg6O7X0S.js → setComponentFile-BilDMtgB.js} +1 -1
  273. package/studio/web/assets/{setup-CUx_aUDl.js → setup-J6qJ7OIU.js} +2 -2
  274. package/studio/web/assets/{status-D7BVKqX9.js → status-0RWGcfyD.js} +1 -1
  275. package/studio/web/assets/{toggleHighContrast-DBSyXzMr.js → toggleHighContrast-BIn-vErT.js} +1 -1
  276. package/studio/web/assets/{tsMode-BByKCjBS.js → tsMode-DgUXku4d.js} +1 -1
  277. package/studio/web/assets/{typescript-DDLnLpw9.js → typescript-C9orXcsM.js} +1 -1
  278. package/studio/web/assets/{useEntityRestURL-31CHGaHk.js → useEntityRestURL-BEoXXbUB.js} +1 -1
  279. package/studio/web/assets/{workers-pR3jRY9D.js → workers-JVzSDmgx.js} +1 -1
  280. package/studio/web/assets/{xml-2iRnMhQO.js → xml-Cq-S8S4X.js} +1 -1
  281. package/studio/web/assets/{yaml-Bf92gJpd.js → yaml-sfoRdh1M.js} +1 -1
  282. package/studio/web/index.html +1 -1
  283. package/utility/errors/hdbError.ts +54 -0
  284. package/utility/hdbTerms.ts +2 -0
  285. package/utility/logging/harper_logger.ts +209 -30
  286. package/utility/logging/logGenerationCoordinator.ts +196 -0
  287. package/utility/logging/logRotation.ts +367 -0
  288. package/utility/logging/logRotator.ts +196 -91
  289. package/utility/npmUtilities.ts +6 -4
  290. package/utility/watcherFallback.ts +0 -122
  291. package/validation/configValidator.ts +6 -3
@@ -20,6 +20,7 @@ import {
20
20
  } from './componentSecrets.ts';
21
21
  import type { SecretsView } from './componentSecrets.ts';
22
22
  import { deployLifecycle } from './deployLifecycle.ts';
23
+ import { thisThreadOwnsApplication } from '../server/threads/isolatedApplications.ts';
23
24
 
24
25
  export class MissingDefaultFilesOptionError extends Error {
25
26
  constructor() {
@@ -68,6 +69,7 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
68
69
  #deployEndHandler: (name: string) => void;
69
70
  #deployInFlight: boolean = false;
70
71
  #restartRequestedDuringDeploy: boolean = false;
72
+ #optionsReady: boolean = false;
71
73
  applicationScope?: ApplicationScope;
72
74
 
73
75
  options: OptionsWatcher;
@@ -241,7 +243,10 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
241
243
 
242
244
  ensureTable<TableResourceType = unknown>(options: any): TableResourceType {
243
245
  options.origin = this.#origin;
244
- return scopedTableFactory(this.applicationScope?.branches)<TableResourceType>(options);
246
+ return scopedTableFactory(
247
+ this.applicationScope?.branches,
248
+ thisThreadOwnsApplication(this.applicationScope?.name)
249
+ )<TableResourceType>(options);
245
250
  }
246
251
 
247
252
  #handleOptionsWatcherReady(): void {
@@ -251,7 +256,21 @@ export class Scope extends EventEmitter<ScopeEventsMap> {
251
256
  // We could make the user call `await scope.ready()` in their `handleApplication` function, but that could lead to the same issue and it'd
252
257
  // be harder for the user to understand why.
253
258
 
259
+ // A second `ready` means the scope had no config of its own and now does — a config file
260
+ // that was unreadable when this worker booted, or one recreated after deletion. Re-emitting
261
+ // reaches nobody: componentLoader is long past its `await scope.ready`, so the component is
262
+ // running on the defaults until something restarts it. Same recovery as the `remove`
263
+ // listener, and the same convention — a plugin with its own `ready` handler owns it.
264
+ const started = this.#optionsReady;
265
+ this.#optionsReady = true;
266
+ const restartNeeded = started && this.listenerCount('ready') === 0;
267
+
254
268
  this.emit('ready');
269
+
270
+ if (restartNeeded) {
271
+ this.#logger.debug?.('Options arrived after the scope started, requesting restart');
272
+ this.requestRestart();
273
+ }
255
274
  }
256
275
 
257
276
  #handleError(error: unknown): void {
@@ -32,8 +32,13 @@ import { restartWorkers, getWorkerIndex } from '../server/threads/manageThreads.
32
32
  import { resetRestartNeeded, subscribeToRestartRequests } from './requestRestart.ts';
33
33
  import { trackScopeClose } from './scopeShutdown.ts';
34
34
  import { deployLifecycle } from './deployLifecycle.ts';
35
- import { assertBranchedDatabases } from './Application.ts';
35
+ import { assertBranchedDatabases, assertIsolationConfig } from './Application.ts';
36
36
  import { prepareBranches } from '../resources/branchDatabase.ts';
37
+ import {
38
+ isIsolatedApplication,
39
+ shouldLoadApplicationHere,
40
+ thisThreadOwnsApplication,
41
+ } from '../server/threads/isolatedApplications.ts';
37
42
  import { toScopeMount, nestScopeMount, type ScopeMount } from './scopeMount.ts';
38
43
  import { scopedImport } from '../security/jsLoader.ts';
39
44
  import { server } from '../server/Server.ts';
@@ -161,6 +166,32 @@ function rootConfigBranchedDatabases(appName: string): string[] | true | undefin
161
166
  return (getConfigObj()?.[appName] as any)?.branchedDatabases;
162
167
  }
163
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
+
164
195
  /**
165
196
  * Resolves the mount for `appName`, or reports the failure and returns `undefined` if the
166
197
  * configured `host`/`urlPath` is invalid. The caller must skip loading the application in that
@@ -268,6 +299,7 @@ export async function loadComponentDirectories(
268
299
  }
269
300
  return;
270
301
  }
302
+ if (!placedOnThisThread(appName)) return;
271
303
  const mountResult = tryRootConfigMount(appName);
272
304
  if (!mountResult.ok) return;
273
305
  const loadedModules = new Set<any>();
@@ -316,6 +348,7 @@ export async function loadComponentDirectories(
316
348
  );
317
349
  continue;
318
350
  }
351
+ if (!placedOnThisThread(appName)) continue;
319
352
  const appFolder = join(CF_ROUTES_DIR, appName);
320
353
  const mountResult = tryRootConfigMount(appName);
321
354
  if (!mountResult.ok) continue;
@@ -347,7 +380,7 @@ export async function loadComponentDirectories(
347
380
  if (hdbAppFolder) {
348
381
  if (getWorkerIndex() === 0) harperLogger.info?.('Loading application from ' + hdbAppFolder);
349
382
  const mountResult = tryRootConfigMount(basename(hdbAppFolder));
350
- if (mountResult.ok) {
383
+ if (mountResult.ok && placedOnThisThread(basename(hdbAppFolder))) {
351
384
  cfsLoaded.push(
352
385
  serializeComponentLoad(hdbAppFolder, () =>
353
386
  loadComponent(hdbAppFolder, cycleResources, hdbAppFolder, {
@@ -849,6 +882,9 @@ export async function loadComponent(
849
882
  if (!componentConfig) continue;
850
883
 
851
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;
852
888
  componentLifecycle.loading(componentStatusName);
853
889
 
854
890
  const subApplicationScope = isRoot
@@ -940,7 +976,10 @@ export async function loadComponent(
940
976
  // our own trusted modules can be directly retrieved from our map, otherwise use the (configurable) secure module loader
941
977
  const ensureTable = (options: any) => {
942
978
  options.origin = origin;
943
- return scopedTableFactory(applicationScope.branches)(options);
979
+ return scopedTableFactory(
980
+ applicationScope.branches,
981
+ thisThreadOwnsApplication(applicationScope.name)
982
+ )(options);
944
983
  };
945
984
  // call the main start hook
946
985
  const network =
@@ -1160,7 +1199,7 @@ export async function loadComponent(
1160
1199
  // — not abort the loop and discard a pending follow-up, like the save that fixes it.
1161
1200
  try {
1162
1201
  await loadComponentDirectories();
1163
- await restartWorkers();
1202
+ await restartWorkers(undefined, undefined, true, null, '*');
1164
1203
  } catch (error) {
1165
1204
  harperLogger.error('Error during component reload', error);
1166
1205
  }
@@ -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;
@@ -55,7 +55,11 @@ type DeploymentStatus =
55
55
  | 'restarting'
56
56
  | 'success'
57
57
  | 'failed'
58
- | 'rolled_back';
58
+ | 'rolled_back'
59
+ // Terminal: the build is complete and certified on disk but was not activated. Terminal rather than
60
+ // in-flight because nothing further happens to THIS deployment — activating its artifact is a separate
61
+ // operator action with a row of its own.
62
+ | 'staged';
59
63
 
60
64
  interface CreateOptions {
61
65
  project?: string;
@@ -63,6 +67,8 @@ interface CreateOptions {
63
67
  user?: string;
64
68
  restart_mode?: 'immediate' | 'rolling' | null;
65
69
  rollback_of?: string | null;
70
+ /** The staged deployment whose artifact this deployment activated. */
71
+ activated_from?: string | null;
66
72
  // Deploy credentials in reference form (`{ registry, secret, scope? }` / `{ host, secret,
67
73
  // username? }`) — never a literal token. Kept so a rollback can re-resolve the credential from
68
74
  // hdb_secret without the operator re-supplying it. Null when the deploy used no credentials or a
@@ -141,6 +147,7 @@ export class DeploymentRecorder {
141
147
  completed_at: null,
142
148
  user: options.user ?? null,
143
149
  rollback_of: options.rollback_of ?? null,
150
+ activated_from: options.activated_from ?? null,
144
151
  credentials: options.credentials ?? null,
145
152
  error: null,
146
153
  };
@@ -465,7 +472,7 @@ export class DeploymentRecorder {
465
472
  this.sealed = true;
466
473
  }
467
474
 
468
- async finish(status: 'success' | 'failed' | 'rolled_back', error?: unknown): Promise<void> {
475
+ async finish(status: 'success' | 'failed' | 'rolled_back' | 'staged', error?: unknown): Promise<void> {
469
476
  if (this.finished) return;
470
477
  // Send a terminal sentinel through the emitter (if any) BEFORE we unsubscribe and
471
478
  // remove it from the registry, so any SSE tail subscribers can resolve their wait