@harperfast/harper 5.3.0-beta.3 → 5.3.0-beta.4

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 (311) hide show
  1. package/bin/cliOperations.ts +25 -3
  2. package/bin/run.ts +18 -0
  3. package/components/Application.ts +52 -78
  4. package/components/DESIGN.md +76 -3
  5. package/components/Scope.ts +10 -4
  6. package/components/anthropic/index.ts +10 -1
  7. package/components/bedrock/index.ts +10 -1
  8. package/components/componentLoader.ts +23 -14
  9. package/components/mcp/tools/operations.ts +3 -1
  10. package/components/ollama/index.ts +10 -1
  11. package/components/openai/index.ts +265 -18
  12. package/components/operations.js +40 -1
  13. package/config/configUtils.ts +3 -19
  14. package/dataLayer/DESIGN.md +29 -5
  15. package/dataLayer/harperBridge/ResourceBridge.ts +39 -3
  16. package/dataLayer/restoreMarker.ts +250 -14
  17. package/dataLayer/schema.ts +2 -7
  18. package/dataLayer/schemaDescribe.ts +10 -0
  19. package/dist/bin/cliOperations.js +28 -3
  20. package/dist/bin/cliOperations.js.map +1 -1
  21. package/dist/bin/run.js +19 -0
  22. package/dist/bin/run.js.map +1 -1
  23. package/dist/components/Application.d.ts +8 -2
  24. package/dist/components/Application.js +43 -69
  25. package/dist/components/Application.js.map +1 -1
  26. package/dist/components/Scope.d.ts +1 -1
  27. package/dist/components/Scope.js +9 -4
  28. package/dist/components/Scope.js.map +1 -1
  29. package/dist/components/anthropic/index.d.ts +0 -10
  30. package/dist/components/anthropic/index.js +9 -1
  31. package/dist/components/anthropic/index.js.map +1 -1
  32. package/dist/components/bedrock/index.d.ts +0 -12
  33. package/dist/components/bedrock/index.js +9 -1
  34. package/dist/components/bedrock/index.js.map +1 -1
  35. package/dist/components/componentLoader.js +23 -14
  36. package/dist/components/componentLoader.js.map +1 -1
  37. package/dist/components/mcp/tools/operations.js +1 -1
  38. package/dist/components/mcp/tools/operations.js.map +1 -1
  39. package/dist/components/ollama/index.d.ts +0 -13
  40. package/dist/components/ollama/index.js +9 -1
  41. package/dist/components/ollama/index.js.map +1 -1
  42. package/dist/components/openai/index.d.ts +11 -15
  43. package/dist/components/openai/index.js +224 -12
  44. package/dist/components/openai/index.js.map +1 -1
  45. package/dist/components/operations.d.ts +9 -0
  46. package/dist/components/operations.js +32 -2
  47. package/dist/components/operations.js.map +1 -1
  48. package/dist/config/configUtils.d.ts +1 -2
  49. package/dist/config/configUtils.js +7 -22
  50. package/dist/config/configUtils.js.map +1 -1
  51. package/dist/dataLayer/harperBridge/ResourceBridge.js +29 -2
  52. package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
  53. package/dist/dataLayer/restoreMarker.d.ts +25 -3
  54. package/dist/dataLayer/restoreMarker.js +213 -13
  55. package/dist/dataLayer/restoreMarker.js.map +1 -1
  56. package/dist/dataLayer/schema.js +1 -4
  57. package/dist/dataLayer/schema.js.map +1 -1
  58. package/dist/dataLayer/schemaDescribe.js +10 -0
  59. package/dist/dataLayer/schemaDescribe.js.map +1 -1
  60. package/dist/index.d.ts +1 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/json/systemSchema.json +28 -0
  63. package/dist/resources/DatabaseTransaction.d.ts +21 -1
  64. package/dist/resources/DatabaseTransaction.js +147 -8
  65. package/dist/resources/DatabaseTransaction.js.map +1 -1
  66. package/dist/resources/PrimaryRocksDatabase.js +1 -1
  67. package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
  68. package/dist/resources/Table.d.ts +31 -3
  69. package/dist/resources/Table.js +397 -79
  70. package/dist/resources/Table.js.map +1 -1
  71. package/dist/resources/auditStore.js +16 -10
  72. package/dist/resources/auditStore.js.map +1 -1
  73. package/dist/resources/blob.d.ts +1 -0
  74. package/dist/resources/blob.js +14 -5
  75. package/dist/resources/blob.js.map +1 -1
  76. package/dist/resources/branchDatabase.js +3 -3
  77. package/dist/resources/branchDatabase.js.map +1 -1
  78. package/dist/resources/databaseDropPreparation.d.ts +20 -0
  79. package/dist/resources/databaseDropPreparation.js +106 -0
  80. package/dist/resources/databaseDropPreparation.js.map +1 -0
  81. package/dist/resources/databases.d.ts +26 -21
  82. package/dist/resources/databases.js +1040 -204
  83. package/dist/resources/databases.js.map +1 -1
  84. package/dist/resources/derivedIndexRegistry.d.ts +23 -0
  85. package/dist/resources/derivedIndexRegistry.js +92 -0
  86. package/dist/resources/derivedIndexRegistry.js.map +1 -1
  87. package/dist/resources/derivedIndexRuntime.d.ts +10 -0
  88. package/dist/resources/derivedIndexRuntime.js +136 -25
  89. package/dist/resources/derivedIndexRuntime.js.map +1 -1
  90. package/dist/resources/derivedIndexes.d.ts +39 -0
  91. package/dist/resources/derivedIndexes.js +733 -0
  92. package/dist/resources/derivedIndexes.js.map +1 -0
  93. package/dist/resources/fullTextSchema.d.ts +8 -0
  94. package/dist/resources/fullTextSchema.js +42 -0
  95. package/dist/resources/fullTextSchema.js.map +1 -1
  96. package/dist/resources/fullTextSchemaLifecycle.d.ts +0 -5
  97. package/dist/resources/fullTextSchemaLifecycle.js +0 -9
  98. package/dist/resources/fullTextSchemaLifecycle.js.map +1 -1
  99. package/dist/resources/graphql.js +101 -9
  100. package/dist/resources/graphql.js.map +1 -1
  101. package/dist/resources/indexes/hnswDerivedIndex.d.ts +0 -10
  102. package/dist/resources/indexes/hnswDerivedIndex.js +0 -230
  103. package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -1
  104. package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.d.ts +3 -0
  105. package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js +57 -8
  106. package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js.map +1 -1
  107. package/dist/resources/models/Models.d.ts +26 -3
  108. package/dist/resources/models/Models.js +256 -13
  109. package/dist/resources/models/Models.js.map +1 -1
  110. package/dist/resources/models/TestBackend.d.ts +3 -1
  111. package/dist/resources/models/TestBackend.js +35 -1
  112. package/dist/resources/models/TestBackend.js.map +1 -1
  113. package/dist/resources/models/analyticsTable.d.ts +2 -2
  114. package/dist/resources/models/analyticsTable.js +4 -2
  115. package/dist/resources/models/analyticsTable.js.map +1 -1
  116. package/dist/resources/models/backendHelpers.d.ts +24 -0
  117. package/dist/resources/models/backendHelpers.js +18 -1
  118. package/dist/resources/models/backendHelpers.js.map +1 -1
  119. package/dist/resources/models/backendRegistry.d.ts +10 -21
  120. package/dist/resources/models/backendRegistry.js +74 -18
  121. package/dist/resources/models/backendRegistry.js.map +1 -1
  122. package/dist/resources/models/bootstrap.d.ts +7 -0
  123. package/dist/resources/models/bootstrap.js +36 -4
  124. package/dist/resources/models/bootstrap.js.map +1 -1
  125. package/dist/resources/models/decideHook.d.ts +33 -0
  126. package/dist/resources/models/decideHook.js +105 -0
  127. package/dist/resources/models/decideHook.js.map +1 -0
  128. package/dist/resources/models/decision.d.ts +64 -0
  129. package/dist/resources/models/decision.js +507 -0
  130. package/dist/resources/models/decision.js.map +1 -0
  131. package/dist/resources/models/decisionStore.d.ts +134 -0
  132. package/dist/resources/models/decisionStore.js +350 -0
  133. package/dist/resources/models/decisionStore.js.map +1 -0
  134. package/dist/resources/models/embedHook.d.ts +66 -8
  135. package/dist/resources/models/embedHook.js +228 -61
  136. package/dist/resources/models/embedHook.js.map +1 -1
  137. package/dist/resources/models/generativeDecision.d.ts +58 -0
  138. package/dist/resources/models/generativeDecision.js +315 -0
  139. package/dist/resources/models/generativeDecision.js.map +1 -0
  140. package/dist/resources/models/types.d.ts +232 -4
  141. package/dist/security/authn/oidc/tokenExchange.js +3 -33
  142. package/dist/security/authn/oidc/tokenExchange.js.map +1 -1
  143. package/dist/security/authn/oidc/tokenUseTable.d.ts +9 -0
  144. package/dist/security/authn/oidc/tokenUseTable.js +28 -0
  145. package/dist/security/authn/oidc/tokenUseTable.js.map +1 -0
  146. package/dist/security/certificateVerification/certificateVerificationSource.d.ts +0 -1
  147. package/dist/security/certificateVerification/certificateVerificationSource.js +3 -3
  148. package/dist/security/certificateVerification/certificateVerificationSource.js.map +1 -1
  149. package/dist/security/certificateVerification/crlVerification.js +77 -165
  150. package/dist/security/certificateVerification/crlVerification.js.map +1 -1
  151. package/dist/security/certificateVerification/types.d.ts +0 -3
  152. package/dist/security/certificateVerification/verificationTables.d.ts +19 -0
  153. package/dist/security/certificateVerification/verificationTables.js +125 -0
  154. package/dist/security/certificateVerification/verificationTables.js.map +1 -0
  155. package/dist/security/certificateVerification/verificationUtils.d.ts +1 -1
  156. package/dist/security/certificateVerification/verificationUtils.js +6 -31
  157. package/dist/security/certificateVerification/verificationUtils.js.map +1 -1
  158. package/dist/security/jsLoader.d.ts +5 -0
  159. package/dist/security/jsLoader.js +8 -0
  160. package/dist/security/jsLoader.js.map +1 -1
  161. package/dist/server/Server.d.ts +1 -0
  162. package/dist/server/Server.js.map +1 -1
  163. package/dist/server/http.js +2 -2
  164. package/dist/server/http.js.map +1 -1
  165. package/dist/server/itc/serverHandlers.js +21 -2
  166. package/dist/server/itc/serverHandlers.js.map +1 -1
  167. package/dist/server/jobs/jobOwnership.d.ts +25 -0
  168. package/dist/server/jobs/jobOwnership.js +127 -0
  169. package/dist/server/jobs/jobOwnership.js.map +1 -0
  170. package/dist/server/jobs/jobProcess.js +9 -2
  171. package/dist/server/jobs/jobProcess.js.map +1 -1
  172. package/dist/server/jobs/jobs.js +18 -5
  173. package/dist/server/jobs/jobs.js.map +1 -1
  174. package/dist/server/loadRootComponents.js +10 -0
  175. package/dist/server/loadRootComponents.js.map +1 -1
  176. package/dist/server/serverHelpers/contentTypes.js +11 -1
  177. package/dist/server/serverHelpers/contentTypes.js.map +1 -1
  178. package/dist/server/serverHelpers/serverHandlers.js +12 -2
  179. package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
  180. package/dist/server/threads/itc.d.ts +4 -1
  181. package/dist/server/threads/itc.js +29 -6
  182. package/dist/server/threads/itc.js.map +1 -1
  183. package/dist/server/threads/manageThreads.d.ts +12 -4
  184. package/dist/server/threads/manageThreads.js +241 -119
  185. package/dist/server/threads/manageThreads.js.map +1 -1
  186. package/dist/server/threads/threadServer.d.ts +1 -0
  187. package/dist/server/threads/threadServer.js +15 -1
  188. package/dist/server/threads/threadServer.js.map +1 -1
  189. package/dist/server/threads/windowsProcessTree.d.ts +91 -0
  190. package/dist/server/threads/windowsProcessTree.js +361 -0
  191. package/dist/server/threads/windowsProcessTree.js.map +1 -0
  192. package/dist/server/throttle.d.ts +1 -1
  193. package/dist/server/throttle.js +8 -1
  194. package/dist/server/throttle.js.map +1 -1
  195. package/dist/upgrade/directives/5-3-0.js +53 -46
  196. package/dist/upgrade/directives/5-3-0.js.map +1 -1
  197. package/dist/utility/errors/hdbError.d.ts +10 -1
  198. package/dist/utility/errors/hdbError.js +55 -11
  199. package/dist/utility/errors/hdbError.js.map +1 -1
  200. package/dist/utility/fsync.d.ts +2 -0
  201. package/dist/utility/fsync.js +20 -0
  202. package/dist/utility/fsync.js.map +1 -0
  203. package/dist/utility/globalSchema.d.ts +18 -0
  204. package/dist/utility/hdbTerms.d.ts +3 -0
  205. package/dist/utility/hdbTerms.js +3 -0
  206. package/dist/utility/hdbTerms.js.map +1 -1
  207. package/dist/utility/signalling.d.ts +7 -1
  208. package/dist/utility/signalling.js +27 -3
  209. package/dist/utility/signalling.js.map +1 -1
  210. package/dist/utility/when.d.ts +1 -0
  211. package/dist/utility/when.js +21 -0
  212. package/dist/utility/when.js.map +1 -1
  213. package/dist/validation/configValidator.js +30 -3
  214. package/dist/validation/configValidator.js.map +1 -1
  215. package/index.ts +13 -0
  216. package/json/systemSchema.json +28 -0
  217. package/npm-shrinkwrap.json +151 -55
  218. package/package.json +14 -13
  219. package/resources/DESIGN.md +80 -100
  220. package/resources/DatabaseTransaction.ts +157 -10
  221. package/resources/PrimaryRocksDatabase.ts +2 -2
  222. package/resources/Table.ts +494 -101
  223. package/resources/auditStore.ts +18 -10
  224. package/resources/blob.ts +13 -6
  225. package/resources/branchDatabase.ts +3 -3
  226. package/resources/databaseDropPreparation.ts +120 -0
  227. package/resources/databases.ts +1155 -205
  228. package/resources/derivedIndexRegistry.ts +122 -0
  229. package/resources/derivedIndexRuntime.ts +157 -30
  230. package/resources/derivedIndexes.ts +856 -0
  231. package/resources/fullTextSchema.ts +55 -0
  232. package/resources/fullTextSchemaLifecycle.ts +0 -15
  233. package/resources/graphql.ts +107 -12
  234. package/resources/indexes/DESIGN.md +7 -0
  235. package/resources/indexes/hnswDerivedIndex.ts +0 -260
  236. package/resources/indexes/nativeFullTextDerivedIndexLifecycle.ts +72 -9
  237. package/resources/models/DESIGN.md +39 -0
  238. package/resources/models/Models.ts +361 -18
  239. package/resources/models/TestBackend.ts +56 -1
  240. package/resources/models/analyticsTable.ts +6 -4
  241. package/resources/models/backendHelpers.ts +17 -0
  242. package/resources/models/backendRegistry.ts +76 -21
  243. package/resources/models/bootstrap.ts +57 -7
  244. package/resources/models/decideHook.ts +135 -0
  245. package/resources/models/decision.ts +505 -0
  246. package/resources/models/decisionStore.ts +419 -0
  247. package/resources/models/embedHook.ts +272 -55
  248. package/resources/models/generativeDecision.ts +459 -0
  249. package/resources/models/types.ts +231 -4
  250. package/security/DESIGN.md +22 -2
  251. package/security/authn/oidc/tokenExchange.ts +6 -34
  252. package/security/authn/oidc/tokenUseTable.ts +27 -0
  253. package/security/certificateVerification/certificateVerificationSource.ts +2 -3
  254. package/security/certificateVerification/crlVerification.ts +96 -174
  255. package/security/certificateVerification/types.ts +0 -3
  256. package/security/certificateVerification/verificationTables.ts +124 -0
  257. package/security/certificateVerification/verificationUtils.ts +8 -32
  258. package/security/jsLoader.ts +9 -1
  259. package/server/DESIGN.md +27 -1
  260. package/server/Server.ts +2 -1
  261. package/server/http.ts +4 -2
  262. package/server/itc/serverHandlers.js +29 -1
  263. package/server/jobs/jobOwnership.ts +89 -0
  264. package/server/jobs/jobProcess.ts +8 -2
  265. package/server/jobs/jobs.ts +15 -4
  266. package/server/loadRootComponents.js +11 -0
  267. package/server/serverHelpers/contentTypes.ts +13 -1
  268. package/server/serverHelpers/serverHandlers.js +11 -2
  269. package/server/threads/itc.js +32 -6
  270. package/server/threads/manageThreads.js +268 -122
  271. package/server/threads/threadServer.js +13 -1
  272. package/server/threads/windowsProcessTree.ts +409 -0
  273. package/server/throttle.ts +11 -1
  274. package/studio/web/assets/{Chat-CveGbxe6.js → Chat-Bq60AO-g.js} +1 -1
  275. package/studio/web/assets/{FloatingChat-IpCFgYWL.js → FloatingChat-D4560T0p.js} +3 -3
  276. package/studio/web/assets/{apiToken-CS8fFTgL.js → apiToken-BEvbFPMc.js} +1 -1
  277. package/studio/web/assets/{applications-D7F4Jopl.js → applications-CSUVTH4E.js} +1 -1
  278. package/studio/web/assets/{cssMode-Daw_oLPq.js → cssMode-DJyc9mHj.js} +1 -1
  279. package/studio/web/assets/{editor-B3Bs1zWX.js → editor-DDIsQfj6.js} +1 -1
  280. package/studio/web/assets/{html-CDaQwWiE.js → html-g1BJHxLy.js} +1 -1
  281. package/studio/web/assets/{htmlMode-Cb6emO4U.js → htmlMode-Vh5IglCQ.js} +1 -1
  282. package/studio/web/assets/{index-B4g2Fu_2.js → index-DGRAzvO4.js} +5 -5
  283. package/studio/web/assets/{index.lazy-NwhvF1q1.js → index.lazy-vgSic7et.js} +1 -1
  284. package/studio/web/assets/{javascript-2_86gB9Q.js → javascript-5VIolqf7.js} +1 -1
  285. package/studio/web/assets/{jsonMode-DX-i86uQ.js → jsonMode-DG4zQraI.js} +1 -1
  286. package/studio/web/assets/{languageServices-B85WN-Ej.js → languageServices-t5FBpX-i.js} +1 -1
  287. package/studio/web/assets/{lspLanguageFeatures-JCWHIsKg.js → lspLanguageFeatures-DgVnNPh-.js} +1 -1
  288. package/studio/web/assets/{notifications-D9ejzt52.js → notifications-BeWcX04m.js} +1 -1
  289. package/studio/web/assets/{notifications-B7hjKhai.js → notifications-DUGWrWoO.js} +1 -1
  290. package/studio/web/assets/{profile-D8B6No3F.js → profile-BvUEDBzW.js} +1 -1
  291. package/studio/web/assets/{regions-DFazIfTK.js → regions-CB-_2m7M.js} +1 -1
  292. package/studio/web/assets/{register-CwFLviLF.js → register-1w1Zr3b2.js} +2 -2
  293. package/studio/web/assets/{setComponentFile-VnJ80SSJ.js → setComponentFile-z4-qJCbA.js} +1 -1
  294. package/studio/web/assets/{setup-BYQxFy-C.js → setup-CS50uJ4x.js} +2 -2
  295. package/studio/web/assets/{status-Cn5XjmsL.js → status-CI0wOdOE.js} +1 -1
  296. package/studio/web/assets/{toggleHighContrast-g9xIh6TX.js → toggleHighContrast-BsAE4jPe.js} +1 -1
  297. package/studio/web/assets/{tsMode-EC-n0Wqc.js → tsMode-D83Gg3cq.js} +1 -1
  298. package/studio/web/assets/{typescript-DHmM9JCO.js → typescript-Dfp-GrNq.js} +1 -1
  299. package/studio/web/assets/{useEntityRestURL-BUdnVSVv.js → useEntityRestURL-BKetlINf.js} +1 -1
  300. package/studio/web/assets/{workers-BVl9bBB-.js → workers-CCvmDLH3.js} +1 -1
  301. package/studio/web/assets/{xml-C4_sqOkX.js → xml-06pZp00U.js} +1 -1
  302. package/studio/web/assets/{yaml-CVkbDqtW.js → yaml-iSnWMVlV.js} +1 -1
  303. package/studio/web/index.html +1 -1
  304. package/upgrade/directives/5-3-0.ts +61 -54
  305. package/utility/DESIGN.md +5 -1
  306. package/utility/errors/hdbError.ts +56 -8
  307. package/utility/fsync.ts +16 -0
  308. package/utility/hdbTerms.ts +3 -0
  309. package/utility/signalling.ts +33 -4
  310. package/utility/when.ts +22 -0
  311. package/validation/configValidator.ts +36 -7
@@ -303,6 +303,8 @@ export function openAuditStore(rootStore) {
303
303
  await removeAuditEntry(auditStore, auditRecord);
304
304
  } catch (error) {
305
305
  harperLogger.warn('Error removing audit entry', error);
306
+ // not continue: the marker and backoff must cover a contiguous removed prefix (DESIGN.md)
307
+ break;
306
308
  }
307
309
  lastKey = auditRecord.key;
308
310
  await new Promise(setImmediate);
@@ -451,21 +453,27 @@ export function removeAuditEntry(auditStore: any, auditRecord: AuditRecord): Pro
451
453
  // at the same time so the audit table the primary table are in sync, assuming the entry is still
452
454
  // the record state this audit record wrote
453
455
  const tableId = auditRecord.tableId;
454
- const primaryStore = auditStore.tableStores[auditRecord.tableId];
455
- const tombstone = primaryStore?.getEntry(auditRecord.recordId);
456
- if (isAuditEntryWrite(tombstone, auditRecord))
457
- // a failed tombstone removal doesn't mean the audit entry removal failed — only
458
- // auditStore.remove() below decides this function's outcome
459
- tombstoneRemoval = new Promise<void>((resolve) => {
460
- resolve(auditStore.deleteCallbacks?.[tableId]?.(auditRecord.recordId, tombstone.version));
461
- }).catch((error) => {
462
- harperLogger.warn('Error removing deleted record while removing its audit entry', error);
463
- });
456
+ // a failed tombstone lookup or removal doesn't mean the audit entry removal failed — only
457
+ // auditStore.remove() below decides this function's outcome. The lookup throws for an
458
+ // undecodable recordId, and that entry would otherwise fail on every cleanup pass.
459
+ try {
460
+ const tombstone = auditStore.tableStores[tableId]?.getEntry(auditRecord.recordId);
461
+ if (isAuditEntryWrite(tombstone, auditRecord))
462
+ tombstoneRemoval = Promise.resolve(
463
+ auditStore.deleteCallbacks?.[tableId]?.(auditRecord.recordId, tombstone.version)
464
+ ).catch(warnTombstoneRemovalFailure);
465
+ } catch (error) {
466
+ warnTombstoneRemovalFailure(error);
467
+ }
464
468
  }
465
469
  const auditRemoval = auditStore.remove(auditRecord.key);
466
470
  return tombstoneRemoval ? Promise.all([tombstoneRemoval, auditRemoval]).then(() => undefined) : auditRemoval;
467
471
  }
468
472
 
473
+ function warnTombstoneRemovalFailure(error: unknown) {
474
+ warnContained('Error removing deleted record while removing its audit entry', error);
475
+ }
476
+
469
477
  function updateLastRemoved(auditStore, lastKey) {
470
478
  FLOAT_TARGET[0] = lastKey;
471
479
  return auditStore.put(Symbol.for('last-removed'), FLOAT_BUFFER);
package/resources/blob.ts CHANGED
@@ -2641,25 +2641,30 @@ export function getBlobPathsForDatabaseName(databaseName: string): string[] {
2641
2641
  }
2642
2642
  export async function deleteRootBlobPathsForDB(store: RootDatabase): Promise<void> {
2643
2643
  const paths = getRootBlobPathsForDB(store);
2644
- if (paths) {
2645
- await Promise.all(paths.map((path) => rimrafSteadily(path)));
2646
- }
2644
+ if (paths) await deleteBlobPaths(paths);
2645
+ }
2646
+
2647
+ export async function deleteBlobPaths(paths: Iterable<string>): Promise<void> {
2648
+ const failures = (await Promise.all([...new Set(paths)].map((path) => rimrafSteadily(path)))).flat();
2649
+ if (failures.length > 0) throw new AggregateError(failures, 'Could not delete blob storage');
2647
2650
  }
2648
2651
 
2649
2652
  /**
2650
2653
  * recursively delete a directory and all of its contents, but do it one at a time, so that we don't run out of memory and hog resources
2651
2654
  * @param path
2652
2655
  */
2653
- async function rimrafSteadily(path: string) {
2654
- if (!existsSync(path)) return;
2656
+ async function rimrafSteadily(path: string): Promise<unknown[]> {
2657
+ if (!existsSync(path)) return [];
2658
+ const failures: unknown[] = [];
2655
2659
  for (const entry of await readdir(path, { withFileTypes: true })) {
2656
2660
  if (entry.isDirectory()) {
2657
- await rimrafSteadily(join(path, entry.name));
2661
+ failures.push(...(await rimrafSteadily(join(path, entry.name))));
2658
2662
  } else {
2659
2663
  try {
2660
2664
  await unlinkPromised(join(path, entry.name));
2661
2665
  } catch (error) {
2662
2666
  logger.warn?.('Error deleting file', error);
2667
+ failures.push(error);
2663
2668
  }
2664
2669
  }
2665
2670
  }
@@ -2667,7 +2672,9 @@ async function rimrafSteadily(path: string) {
2667
2672
  await rmdir(path);
2668
2673
  } catch (error) {
2669
2674
  logger.warn?.('Error deleting directory', error);
2675
+ failures.push(error);
2670
2676
  }
2677
+ return failures;
2671
2678
  }
2672
2679
  function getFilePath({ storageIndex, fileId, store }: StorageInfo): string {
2673
2680
  const blobStoragePaths = getRootBlobPathsForDB(store);
@@ -504,7 +504,7 @@ async function openOrCreate(baseName: string, appName: string, branchPath: strin
504
504
  // The branch is closed first — it holds the path and store identity a retry needs — and
505
505
  // a close failure must not leave the claim wedged in CREATING for the whole deadline.
506
506
  try {
507
- branch?.close();
507
+ await branch?.close();
508
508
  } catch (closeError) {
509
509
  logger.warn(`Error closing branch at ${branchPath} after a failed open`, closeError);
510
510
  }
@@ -575,7 +575,7 @@ export async function closeBranchAt(branchPath: string): Promise<void> {
575
575
  const pending = branchesByPath.get(branchPath);
576
576
  branchesByPath.delete(branchPath);
577
577
  const opened = await pending?.catch(() => null);
578
- opened?.branch.close();
578
+ await opened?.branch.close();
579
579
  }
580
580
 
581
581
  /**
@@ -737,7 +737,7 @@ async function removeBranchAt(branchPath: string): Promise<void> {
737
737
  const pending = branchesByPath.get(branchPath);
738
738
  branchesByPath.delete(branchPath);
739
739
  const opened = (await pending?.catch(() => null)) ?? null;
740
- opened?.branch.close();
740
+ await opened?.branch.close();
741
741
  await destroyBranchStorage(branchPath, opened);
742
742
  }
743
743
 
@@ -0,0 +1,120 @@
1
+ import { threadId, workerData } from 'node:worker_threads';
2
+ import { dirname, resolve } from 'node:path';
3
+
4
+ type DatabaseDropPreparation = {
5
+ id: string;
6
+ ownerThreadId: number;
7
+ databaseName: string;
8
+ ownerExited?: boolean;
9
+ preparationTask?: Promise<void>;
10
+ };
11
+
12
+ const inheritedDatabaseDropPreparations = (workerData?.databaseDropPreparations ?? []).filter(
13
+ // Main reaches a child through parentPort rather than addThreadIds; worker owners must be in the initial peer topology.
14
+ ([, preparation]: [string, DatabaseDropPreparation]) =>
15
+ preparation.ownerThreadId === 0 || workerData?.addThreadIds?.includes(preparation.ownerThreadId)
16
+ );
17
+ const databaseDropPreparations = new Map<string, DatabaseDropPreparation>(inheritedDatabaseDropPreparations);
18
+
19
+ class DatabaseDroppingError extends Error {
20
+ statusCode = 409;
21
+ code = 'DATABASE_DROP_IN_PROGRESS';
22
+ retryable = true;
23
+ constructor(databaseName: string) {
24
+ super(`Database '${databaseName}' is already being dropped`);
25
+ this.name = 'DatabaseDroppingError';
26
+ }
27
+ }
28
+
29
+ export function claimDatabaseDropPreparation(
30
+ rootPath: string,
31
+ preparationId: string,
32
+ ownerThreadId = threadId,
33
+ databaseName = rootPath
34
+ ): boolean {
35
+ const current = databaseDropPreparations.get(rootPath);
36
+ if (current?.id === preparationId) return false;
37
+ if (current) {
38
+ throw new DatabaseDroppingError(current.databaseName);
39
+ }
40
+ databaseDropPreparations.set(rootPath, { id: preparationId, ownerThreadId, databaseName });
41
+ return true;
42
+ }
43
+
44
+ export function releaseDatabaseDropPreparation(rootPath: string, preparationId: string): void {
45
+ if (databaseDropPreparations.get(rootPath)?.id === preparationId) databaseDropPreparations.delete(rootPath);
46
+ }
47
+
48
+ export function claimDatabaseDropPreparations(
49
+ rootPaths: Iterable<string>,
50
+ preparationId: string,
51
+ ownerThreadId = threadId,
52
+ databaseName?: string
53
+ ): void {
54
+ const claimed: string[] = [];
55
+ try {
56
+ for (const rootPath of new Set(rootPaths)) {
57
+ if (claimDatabaseDropPreparation(rootPath, preparationId, ownerThreadId, databaseName)) claimed.push(rootPath);
58
+ }
59
+ } catch (error) {
60
+ for (const rootPath of claimed) releaseDatabaseDropPreparation(rootPath, preparationId);
61
+ throw error;
62
+ }
63
+ }
64
+
65
+ export function releaseDatabaseDropPreparations(rootPaths: Iterable<string>, preparationId: string): void {
66
+ for (const rootPath of new Set(rootPaths)) releaseDatabaseDropPreparation(rootPath, preparationId);
67
+ }
68
+
69
+ export function trackDatabaseDropPreparationTask(
70
+ rootPath: string,
71
+ preparationId: string,
72
+ preparationTask: Promise<void>
73
+ ): void {
74
+ const preparation = databaseDropPreparations.get(rootPath);
75
+ if (preparation?.id !== preparationId) return;
76
+ preparation.preparationTask = preparationTask;
77
+ if (preparation.ownerExited) {
78
+ const release = () => releaseDatabaseDropPreparation(rootPath, preparationId);
79
+ preparationTask.then(release, release);
80
+ }
81
+ }
82
+
83
+ export function handleDatabaseDropPreparationOwnerExit(ownerThreadId: number): void {
84
+ for (const [rootPath, preparation] of databaseDropPreparations) {
85
+ if (preparation.ownerThreadId !== ownerThreadId) continue;
86
+ preparation.ownerExited = true;
87
+ if (preparation.preparationTask) {
88
+ const release = () => releaseDatabaseDropPreparation(rootPath, preparation.id);
89
+ preparation.preparationTask.then(release, release);
90
+ } else databaseDropPreparations.delete(rootPath);
91
+ }
92
+ }
93
+
94
+ export function databaseDropPrepared(rootPath: string): boolean {
95
+ return databaseDropPreparations.size > 0 && databaseDropPreparations.has(rootPath);
96
+ }
97
+
98
+ export function databaseDropPreparedWithin(directoryPath: string): boolean {
99
+ if (databaseDropPreparations.size === 0) return false;
100
+ const normalizedDirectoryPath = resolve(directoryPath);
101
+ for (const rootPath of databaseDropPreparations.keys()) {
102
+ if (resolve(dirname(rootPath)) === normalizedDirectoryPath) return true;
103
+ }
104
+ return false;
105
+ }
106
+
107
+ export function databaseDropPreparationSnapshot(): [
108
+ string,
109
+ Pick<DatabaseDropPreparation, 'id' | 'ownerThreadId' | 'databaseName'>,
110
+ ][] {
111
+ const snapshot: [string, Pick<DatabaseDropPreparation, 'id' | 'ownerThreadId' | 'databaseName'>][] = [];
112
+ for (const [rootPath, preparation] of databaseDropPreparations) {
113
+ if (!preparation.ownerExited)
114
+ snapshot.push([
115
+ rootPath,
116
+ { id: preparation.id, ownerThreadId: preparation.ownerThreadId, databaseName: preparation.databaseName },
117
+ ]);
118
+ }
119
+ return snapshot;
120
+ }